STL里的容器要求只能是一种类型,比如 vector<int> v; 这个数组里就只能放int型数据,换了其它的数据,一不认识,二如果大了还放不下,当然,大多数情况不需要这样的功能,我要的就是一个int的数组,我疯了还往里面push一个浮点数?我也暂时没想到需要在一个容器里放多种类型数据的应用场合,至少这种要求也并不过分,就当是考验一下C++,它能做到吗? boost::any库肯定的回答了这个问题,从名字上看,它能放下任何类型的数据,口气不小.可以这样定义: using namespace boost;vector<any> v; v.push_back(any(100));v.push_back(any(3.14)); boost的源码是免费的,下来打开看就知道了,整份源码只有200多行,很简洁很强大!它内嵌有一个基类placeholder,不做任何事,然后还有一个模板类holder<T>,它从placeholder派生下来,holder<T>是对T的一个封装,有一个成员就是T held,数据本身,然后在any类里面有一个placeholder的指针,基类指针可以指向任何子类成员,即holder<T>的对象,而holder<T>可以具现成任何类型T的一个holder - - (很简洁很强大吧) 画个图 placeholder指针-> 任意类型的holder holder<int>, holder<float> ... 这些都容易,但有一个问题,在需要一个容器放多种类型数据的时候,需要做一件事,运行时类型检查,vector的设计没有考虑这个,所以这件事自然落在any的身上,any也没什么怪招,实际上是C++的支持,对RTTI的支持.从any的对象中取数据,需要一个操作,any_cast,同时,它也完成了类型检查,any_cast是一个友元,传入一个any*,返回一个ValueType*,ValueType是一个模板参数,代码是这样的: template<typename ValueType> ValueType * any_cast(any * operand) { return operand && operand->type() == typeid(ValueType) ? &static_cast<any::holder<ValueType> *>(operand->content)->held : 0; } typeid是C++的操作符,返回的是一个std::type_info&数据,传入一个类型名或者表达式,如果是两个相同类型则==操作符返回真,上面的代码就是,先做类型检查,如果类型相同,则返回数据的地址,否则返回0. 对了,any的构造函数采用new 操作,则所有数据都是从堆上分配,我想既然STL有专门优化过的allocator,为什么不用,而用原始的new?完全可以为any添加一个模板参数,指定分配器,这并不会使它看上去更复杂. 具体对any库的使用,尤其是any_cast的使用,见boost文档中的例程,不再话下. 附上刚才对typeid测试的程序,它可以做动态类型检测,只有当类中存在虚函数时,这似乎可以暗示我们,它是如何实现的. #include <cstdlib>#include <iostream> using namespace std; class Base{ public: virtual void foo(){}}; class Derived : public Base{ public: void foo(){}}; int main(int argc, char *argv[]){ Base *pB=new Derived; cout<<typeid(pB).name()<<endl <<typeid(*pB).name()<<endl <<(typeid(Base)==typeid(Derived))<<endl <<typeid(Base).before(typeid(Derived))<<endl; delete pB; /* pB=0; cout<<typeid(*pB).name()<<endl; //在没有添加虚函之前,这段代码可以运行,因为它是静态的,在编译期就把*pB的类型确定了,实际上并没有执行对0指针的引用,添加之后,就是动态类型了,程序异常结束 */ system("PAUSE"); return EXIT_SUCCESS;} rickone 2008/01/31

评论