boost::any的用法、优点和缺点以及源代码分析

来源:互联网 发布:美国黑人比例 知乎 编辑:程序博客网 时间:2024/04/29 08:23

boost::any用法示例:

view plaincopy to clipboardprint?
#include <iostream>  
#include <list>  
#include <boost/any.hpp>  
 
typedef std::list<boost::any> list_any;  
 
//关键部分:可以存放任意类型的对象  
void fill_list(list_any& la)  
{      
    la.push_back(10);//存放常数   
    la.push_back( std::string("dyunze") );//存放字符串对象;注意la.push_back(“dyunze”)错误,因为会被当错字符串数组  
}  
 
//根据类型进行显示  
void show_list(list_any& la)  
{  
    list_any::iterator it;  
    boost::any anyone;  
 
    for( it = la.begin(); it != la.end(); it++ )  
    {     
        anyone = *it;  
 
        if( anyone.type() == typeid(int) )  
            std::cout<<boost::any_cast<int>(*it)<<std::endl;  
        else if( anyone.type() == typeid(std::string) )  
            std::cout<<boost::any_cast<std::string>(*it).c_str()<<std::endl;  
    }  
}  
 
int main()  
{  
    list_any la;  
    fill_list(la);  
    show_list(la);  
 
    return 0;  

#include <iostream>
#include <list>
#include <boost/any.hpp>

typedef std::list<boost::any> list_any;

//关键部分:可以存放任意类型的对象
void fill_list(list_any& la)
{   
 la.push_back(10);//存放常数
 la.push_back( std::string("dyunze") );//存放字符串对象;注意la.push_back(“dyunze”)错误,因为会被当错字符串数组
}

//根据类型进行显示
void show_list(list_any& la)
{
 list_any::iterator it;
 boost::any anyone;

 for( it = la.begin(); it != la.end(); it++ )
 { 
  anyone = *it;

  if( anyone.type() == typeid(int) )
   std::cout<<boost::any_cast<int>(*it)<<std::endl;
  else if( anyone.type() == typeid(std::string) )
   std::cout<<boost::any_cast<std::string>(*it).c_str()<<std::endl;
 }
}

int main()
{
 list_any la;
 fill_list(la);
 show_list(la);

 return 0;
}

boost::any的优点:

     对设计模式理解的朋友都会知道合成模式。因为多态只有在使用指针或引用的情况下才能显现,所以std容器中只能存放指针或引用(但实际上只能存放指针,无法存放引用,这个好像是c++的不足吧)。如:

     std::list<BaseClass*> mylist;

这样,我们就要对指针所指向内容的生存周期操心(可能需要程序员适时删除申请的内存;但是由于存放指针,插入/删除的效率高),而使用boost::any就可能避免这种情况,因为我们可以存放类型本身(当然存放指针也可以)。这是boost::any的优点之一。

    boost::any另一个优点是可以存放任何类型。而前面提到的mylist只能存放BaseClass类指针以及其继承类的指针。

boost::any的缺点:

    由于boost::any可以存放任何类型,自然它用不了多态特性,没有统一的接口,所以在获取容器中的元素时需要实现判别元素的真正类型,这增加了程序员的负担。与面向对象编程思想有些矛盾,但整个标准c++模板库何尝不是如此,用那些牛人的话来说,是“有益补充”。

   总之,有利必有弊,没有十全十美的。

  

分析并模仿boost::any:

     读了一下boost::any的源代码,并模仿一下其实现(相当一部分时拷贝原代码),下面是代码(只包含必要功能)。

实现any的功能主要由三部分组成:
1)any类
2)真正保存数据的holder类及其基类placeholder
3)获取真正数据的模板函数any_cast,类型转换的功能。

view plaincopy to clipboardprint?
#include <iostream>  
#include <list>  
#include <cassert>  
 
//自定义的any类  
class any  
{  
public:  
      
    //保存真正数据的接口类  
    class placeholder  
    {  
    public:       
        virtual ~placeholder()  
        {  
        }  
    public:   
 
        virtual const std::type_info & type() const = 0;  
        virtual placeholder * clone() const = 0;      
    };  
 
    //真正保存和获取数据的类。  
    template<typename ValueType>  
    class holder : public placeholder  
    {  
    public:           
        holder(const ValueType & value): held(value)  
        {  
        }  
 
    public:   
 
        virtual const std::type_info & type() const 
        {  
            return typeid(ValueType);  
        }  
 
        virtual placeholder * clone() const 
        {  
            return new holder(held);//使用了原型模式  
        }  
 
    public:   
 
        //真正的数据,就保存在这里  
        ValueType held;  
    };  
 
public:  
 
    any(): content(NULL)     
    {         
    }  
 
    //模板构造函数,参数可以是任意类型,真正的数据保存在content中  
    template<typename ValueType>  
    any(const ValueType & value): content(new holder<ValueType>(value))  
    {  
    }    
 
    //拷贝构造函数  
    any(const any & other)  
        : content(other.content ? other.content->clone() : 0)  
    {  
    }  
 
    //析构函数,删除保存数据的content对象  
    ~any()  
    {  
        if(NULL != content)  
            delete content;  
    }  
 
private:  
    //一个placeholde对象指针,指向其子类folder的一个实现  
    // 即content( new holder<ValueType>(value) )语句  
    placeholder* content;  
 
    template<typename ValueType> friend ValueType any_cast(const any& operand);  
public:   
 
    //查询真实数据的类型。  
    const std::type_info & type() const 
    {  
        return content ? content->type() : typeid(void);  
    }  
};  
 
 
//获取content->helder数据的方法。用来获取真正的数据  
template<typename ValueType>  
ValueType any_cast(const any& operand)  
{  
    assert( operand.type() == typeid(ValueType) );  
    return static_cast<any::holder<ValueType> *>(operand.content)->held;  
}  
 
//下代码是使用示例  
 
typedef std::list<any> list_any;  
 
void fill_list(list_any& la)  
{      
    la.push_back(10);//存放常数;调用了any的模板构造函数,下同  
    la.push_back( std::string("我是string") );//存放字符串对象;注意la.push_back(“dyunze”)错误,因为会被当错字符串数组  
 
    char* p = "我是常量区字符串abc";  
    la.push_back(p);//可以存放指针,但要注意指针的失效问题  
}  
 
//根据类型进行显示  
void show_list(list_any& la)  
{  
    list_any::iterator it;  
 
    for( it = la.begin(); it != la.end(); it++ )  
    {     
 
        if( (*it).type() == typeid(int) )  
            std::cout<<any_cast<int>(*it)<<std::endl;  
        else if( (*it).type() == typeid(std::string) )  
            std::cout<<any_cast<std::string>(*it).c_str()<<std::endl;  
        else if( (*it).type() == typeid(char*) )  
            std::cout<<any_cast<char*>(*it)<<std::endl;  
    }  
}  
 
int main()  
{  
    list_any la;  
    fill_list(la);  
    show_list(la);  
 
    return 0;  

#include <iostream>
#include <list>
#include <cassert>

//自定义的any类
class any
{
public:
 
 //保存真正数据的接口类
 class placeholder
 {
 public:    
  virtual ~placeholder()
  {
  }
 public:

  virtual const std::type_info & type() const = 0;
  virtual placeholder * clone() const = 0;   
 };

 //真正保存和获取数据的类。
 template<typename ValueType>
 class holder : public placeholder
 {
 public:        
  holder(const ValueType & value): held(value)
  {
  }

 public:

  virtual const std::type_info & type() const
  {
   return typeid(ValueType);
  }

  virtual placeholder * clone() const
  {
   return new holder(held);//使用了原型模式
  }

 public:

  //真正的数据,就保存在这里
  ValueType held;
 };

public:

 any(): content(NULL)  
 {      
 }

 //模板构造函数,参数可以是任意类型,真正的数据保存在content中
 template<typename ValueType>
 any(const ValueType & value): content(new holder<ValueType>(value))
 {
 } 

 //拷贝构造函数
 any(const any & other)
  : content(other.content ? other.content->clone() : 0)
 {
 }

 //析构函数,删除保存数据的content对象
 ~any()
 {
  if(NULL != content)
   delete content;
 }

private:
 //一个placeholde对象指针,指向其子类folder的一个实现
 // 即content( new holder<ValueType>(value) )语句
 placeholder* content;

 template<typename ValueType> friend ValueType any_cast(const any& operand);
public:

 //查询真实数据的类型。
 const std::type_info & type() const
 {
  return content ? content->type() : typeid(void);
 }
};


//获取content->helder数据的方法。用来获取真正的数据
template<typename ValueType>
ValueType any_cast(const any& operand)
{
 assert( operand.type() == typeid(ValueType) );
 return static_cast<any::holder<ValueType> *>(operand.content)->held;
}

//下代码是使用示例

typedef std::list<any> list_any;

void fill_list(list_any& la)
{   
 la.push_back(10);//存放常数;调用了any的模板构造函数,下同
 la.push_back( std::string("我是string") );//存放字符串对象;注意la.push_back(“dyunze”)错误,因为会被当错字符串数组

 char* p = "我是常量区字符串abc";
 la.push_back(p);//可以存放指针,但要注意指针的失效问题
}

//根据类型进行显示
void show_list(list_any& la)
{
 list_any::iterator it;

 for( it = la.begin(); it != la.end(); it++ )
 { 

  if( (*it).type() == typeid(int) )
   std::cout<<any_cast<int>(*it)<<std::endl;
  else if( (*it).type() == typeid(std::string) )
   std::cout<<any_cast<std::string>(*it).c_str()<<std::endl;
  else if( (*it).type() == typeid(char*) )
   std::cout<<any_cast<char*>(*it)<<std::endl;
 }
}

int main()
{
 list_any la;
 fill_list(la);
 show_list(la);

 return 0;
}

参考文献:

1)http://www.nohack.cn/code/other/2006-10-05/10230.html

2)boost::any源代码

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/hityct1/archive/2009/05/14/4186962.aspx