boost::any的使用和扩展

前言

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_NAME
            std::strcmp(operand->type().name(), typeid(ValueType).name()) == 0
#else
            operand->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指针来存放这个数据,然后智能地释放掉上次那个数据的空间,详细看代码注释。


  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值