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指针来存放这个数据,然后智能地释放掉上次那个数据的空间,详细看代码注释。

时间: 2024-10-10 16:50:27

boost::any的使用和扩展的相关文章

GoogleCpp风格指南 5) 其他特性_part3

[Add] Lambda expressions 在合适的时候使用lambda表达式; 不要使用默认的lambda captures, 使用显式的captures; [http://en.cppreference.com/w/cpp/language/lambda ] 定义: lambda表达式是一个创建匿名函数对象anonymous function objects.的简洁concise方式; 在将函数作为参数传递的时候很有用; 1 2 3 std::sort(v.begin(), v.end

利用boost.python 通过c++语言来扩展python (python.boost)

python语言的优良性就不多说了,我想提下如何使用boost.python,通过boost.python既可以将python转移到C++上,通过Python库,也可以通过C++来扩展python,下面主要介绍使用boost.python来扩展python的功能,第一次用boost.python,倒腾了半天才搞定: 首先列出我的测试环境: 我用的是VS2010,python2.7,我用VS2010创建了一个windows DLL的项目,项目名称为pylib,在DLL main中加入如下代码: /

利用C++ Boost编写扩展Python模块

Python很强大,但已有的模块可能满足不了人民日益增长的物质文化需求,于是有时需要编写扩展模块进行完善. 可行的方案有很多:SWIG.Weave.ctypes.BOOST-- BOOST无疑是开发最快的一种方案.下面介绍下最简单的C++ helloworld程序如何变为Python的一个模块. 1. 安装Python.Boost 这里用Linux环境.Python和Boost都用源码安装,网址为: Python2.6:https://www.python.org BOOST1.57.0:htt

C++使用boost.python编写Python扩展

很久没有写文章了,今天整理了一些东西,在这里分享一下. 最近一直在想用C++封装一些在工作中常用的Python扩展模块,因为之前没有用C++写过类似的东西,因此一直在网上找一些文章,但是我发现好多文章都描述的不是很清晰,对于老鸟来说应该会很容易,但是像我这种初学者,肯定会造成很大的困扰,因为总是出现很多的报错,搞的头很大,因此我将成功的案例分享一下,并且详细的解释下让我产生疑惑的地方. boost.python 简单描述 C++写python扩展模块有很多种方式,我选择的是boost.pytho

python/c++接口库比较(SWIG,boost.python, pycxx, py++, sip, Weave, Pyrex )

<python/c++接口库比较(SWIG,boost.python, pycxx, py++, sip, Weave, Pyrex )>http://blog.csdn.net/lainegates/article/details/19565823 目前有很多开源的Python/c++ 绑定工具,搜了好多岾子,这里稍微总结下. SWIG 支持 Python 2 and 3 配置正确的话,可以全自动完成封装(*.i文件需要自己写) 当不是全自动的时候,它大多会重复你的.h文件并给出提示 除了P

boost的property_tree组件

1.1 缘起 stl中对线性表有充分的实现,无论是vector还是list都是典型的线性表,即便是set和map,尽管实现上采用了诸如红黑树之类的树形结构,但那仅仅是为了快速检索的需要,从语义上来说它们依旧是线性表,无法表达目录树这种树形结构.boost中的property_tree可以看做是对树形结构实现的补充,我们大可把它扩展应用到各种需要树形结构的地方. 当我们拥有了一个树性结构以后,那么也就同时拥有了树形结构中的每个节点的访问权,很自然的,我们希望每个节点都可以方便的检索(类似于输入一个

Boost::Asio入门剖析

Boost::Asio可以在socket等I/O对象上执行同步或异步操作,使用Boost::Asio前很有必要了解Boost::Asio.你的程序以及它们交互的过程. 作为一个引导的例子,我们思考一个当一个socket执行连接操作时发生了什么,我们首先开始一个同步的例子 你的程序需要一个io_service对象,io_service把你的程序和操作系统I/O设备链接起来. boost::asio::io_service io_service; 你的程序需要一个I/O对象来执行I/O操作,比如tc

boost之date_time库

最近开了boost库的学习,就先从日期时间库开始吧,boost的date_time库是一个很强大的时间库,用起来还是挺方便的.以下算是我学习的笔记,我把它记录下来,以后便于我复习和查阅. #include<iostream>#include<boost/date_time/gregorian/greg_month.hpp>#include<boost/date_time/gregorian/gregorian.hpp> using namespace std;using

最常用的两种C++序列化方案的使用心得(protobuf和boost serialization)

导读 1. 什么是序列化? 2. 为什么要序列化?好处在哪里? 3. C++对象序列化的四种方法 4. 最常用的两种序列化方案使用心得 正文 1. 什么是序列化? 程序员在编写应用程序的时候往往需要将程序的某些数据存储在内存中,然后将其写入某个文件或是将它传输到网络中的另一台计算机上以实现通讯.这个将 程序数据转化成能被存储并传输的格式的过程被称为"序列化"(Serialization),而它的逆过程则可被称为"反序列化" (Deserialization). 简单