Jelin的博客专栏

前言

boost::any类为我们提供了一个十分强大的功能:只要定义一个any对象,就可以保存任意类型的数据到这个对象中,而且还可以动态改变类型。这比我么在COM中使用到的VARIANT结构要强大多了,VARIANT只不过是用到了一个联合体,把可能出现的类型全部包括进去了,更像是一种穷举,而且还有一个标识来说明当前结构中保存的数据的类型。

如何使用any?

去boost官网下载对应的ZIP包,解压后运行那个exe编译完成后,把对应的头文件和库文件路径添加到VS的路径里面去。

然后包括下这个头文件即可

#include <boost/any.hpp>

简单的测试代码

<span style="white-space:pre"></span>boost::any a1 = 123;if ( a1.empty() )cout<<"a1容器不为空"<<endl;else cout<<"a1容器为空"<<endl;a1 = string("string::123");a1 = 12.398;if ( !a1.empty() ){cout<<"now a1 = "<<a1<<", a1.type = "<<typeid(a1).name()<<endl;}直接这样编译是会报错的,在C++中除了标准库定义的类外,我们自己定义的类使用<<\&;>标准输入输出流时需要自己来重载<<操作符的。至于重载函数的写法,基本上都是这样的:作为类的友元函数,传入一个ostream对象的引用,输出后返回这个引用。

ostream& operator <<( ostream& out, const boost::any& a ){if ( a.type() == typeid(int) )out<<boost::any_cast<int>(a);else if ( a.type() == typeid(string) )out<<boost::any_cast<string>(a);else if ( a.type() == typeid(double) )out<<boost::any_cast<double>(a);else if ( a.type() == typeid(float) )out<<boost::any_cast<float>(a);//这里如果未把any对应的类型进行处理将直接跳过,不能输出任何信息return out;}因为我们不知道any的类型,需要借助any_cast来转换,查看any_cast的源码

template<typename ValueType>ValueType * any_cast(any * operand){return operand && #ifdef BOOST_AUX_ANY_TYPE_ID_NAMEstd::strcmp(operand->type().name(), typeid(ValueType).name()) == 0#elseoperand->type() == typeid(ValueType)#endif? &static_cast<any::holder<ValueType> *>(operand->content)->held: 0;}代码的意思:如果any指针不为空,而且它的类型和我们传入的类型一致,那么返回any中保存的那个数据的地址;否则,返回空指针。

any=内部如何实现的呢?

看了下源代码,依葫芦画瓢写了个差不多的类

class MyAny{public://默认构造函数MyAny():m_pValue(NULL){}template<class T>MyAny(const T& t):m_pValue(new CValue<T>(t)){}//拷贝构造函数MyAny(MyAny& ma):m_pValue(ma.IsEmpty()?NULL:ma.m_pValue->Clone()){}virtual ~MyAny(){if ( m_pValue ){delete m_pValue;}}MyAny& Swap(MyAny& ma){//交换两个对象的地址,避免了重新申请释放内存,提高效率std::swap( ma.m_pValue, m_pValue);return *this;}template<class T>MyAny& operator=(const T& val){//重载=操作符,先是构造一个MyAny对象,Awap交换对象指针后,原来需要释放的那个指针就到了临时对象MyAny(val)中//函数返回后,临时变量自动析构,调用了析构函数释放这块内存,不会造成内存泄露。MyAny(val).Swap(*this);return *this;}bool IsEmpty(){return !m_pValue;}protected://基类声明class IValueBase{public:virtual const char* GetTypeName()= 0;virtual IValueBase*Clone()= 0;};//子类扩展为模板类template<class TypeName>class CValue: public IValueBase{public:CValue(const TypeName& val):_value(val){}virtual const char* GetTypeName(){return typeid(TypeName).name();}virtual IValueBase*Clone(){//拷贝一份数据return new CValue<TypeName>(_value);}private://模板类对象中存储着any数据TypeName_value;};private://虚基类的指针,指向一个派生的模板类对象IValueBase* m_pValue;//重载操作符,用于C++的格式化输出,定义为友元函数friend ostream& operator<<(ostream& out, const MyAny& ma);};

//重载函数,用于标准输出

ostream& operator<<(ostream& out, const MyAny& ma){out<<ma.m_pValue->GetTypeName();return out;}

any中保存着一个基类的指针,创建的时候其实是指向了他的派生类对象,派生类是模板类。

真正的数据保存和交换都是在派生类CValue中的。any会根据构造函数或者赋值函数传入的数据类型创建一个IValueBase指针来存放这个数据,然后智能地释放掉上次那个数据的空间,,详细看代码注释。

你不能左右天气,但你能转变你的心情

Jelin的博客专栏

相关文章:

你感兴趣的文章:

标签云: