zoukankan      html  css  js  c++  java
  • <转>boost::any的用法、优点和缺点以及源代码分析

    01.#include <iostream>  
    02.#include <list>  
    03.#include <boost/any.hpp>  
    04. 
    05.typedef std::list<boost::any> list_any;  
    06. 
    07.//关键部分:可以存放任意类型的对象  
    08.void fill_list(list_any& la)  
    09.{      
    10.    la.push_back(10);//存放常数   
    11.    la.push_back( std::string("dyunze") );//存放字符串对象;注意la.push_back(“dyunze”)错误,因为会被当错字符串数组  
    12.}  
    13. 
    14.//根据类型进行显示  
    15.void show_list(list_any& la)  
    16.{  
    17.    list_any::iterator it;  
    18.    boost::any anyone;  
    19. 
    20.    for( it = la.begin(); it != la.end(); it++ )  
    21.    {     
    22.        anyone = *it;  
    23. 
    24.        if( anyone.type() == typeid(int) )  
    25.            std::cout<<boost::any_cast<int>(*it)<<std::endl;  
    26.        else if( anyone.type() == typeid(std::string) )  
    27.            std::cout<<boost::any_cast<std::string>(*it).c_str()<<std::endl;  
    28.    }  
    29.}  
    30. 
    31.int main()  
    32.{  
    33.    list_any la;  
    34.    fill_list(la);  
    35.    show_list(la);  
    36. 
    37.    return 0;  
    38.} 
    #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?
    01.#include <iostream>  
    02.#include <list>  
    03.#include <cassert>  
    04. 
    05.//自定义的any类  
    06.class any  
    07.{  
    08.public:  
    09.      
    10.    //保存真正数据的接口类  
    11.    class placeholder  
    12.    {  
    13.    public:       
    14.        virtual ~placeholder()  
    15.        {  
    16.        }  
    17.    public:   
    18. 
    19.        virtual const std::type_info & type() const = 0;  
    20.        virtual placeholder * clone() const = 0;      
    21.    };  
    22. 
    23.    //真正保存和获取数据的类。  
    24.    template<typename ValueType>  
    25.    class holder : public placeholder  
    26.    {  
    27.    public:           
    28.        holder(const ValueType & value): held(value)  
    29.        {  
    30.        }  
    31. 
    32.    public:   
    33. 
    34.        virtual const std::type_info & type() const 
    35.        {  
    36.            return typeid(ValueType);  
    37.        }  
    38. 
    39.        virtual placeholder * clone() const 
    40.        {  
    41.            return new holder(held);//使用了原型模式  
    42.        }  
    43. 
    44.    public:   
    45. 
    46.        //真正的数据,就保存在这里  
    47.        ValueType held;  
    48.    };  
    49. 
    50.public:  
    51. 
    52.    any(): content(NULL)     
    53.    {         
    54.    }  
    55. 
    56.    //模板构造函数,参数可以是任意类型,真正的数据保存在content中  
    57.    template<typename ValueType>  
    58.    any(const ValueType & value): content(new holder<ValueType>(value))  
    59.    {  
    60.    }    
    61. 
    62.    //拷贝构造函数  
    63.    any(const any & other)  
    64.        : content(other.content ? other.content->clone() : 0)  
    65.    {  
    66.    }  
    67. 
    68.    //析构函数,删除保存数据的content对象  
    69.    ~any()  
    70.    {  
    71.        if(NULL != content)  
    72.            delete content;  
    73.    }  
    74. 
    75.private:  
    76.    //一个placeholde对象指针,指向其子类folder的一个实现  
    77.    // 即content( new holder<ValueType>(value) )语句  
    78.    placeholder* content;  
    79. 
    80.    template<typename ValueType> friend ValueType any_cast(const any& operand);  
    81.public:   
    82. 
    83.    //查询真实数据的类型。  
    84.    const std::type_info & type() const 
    85.    {  
    86.        return content ? content->type() : typeid(void);  
    87.    }  
    88.};  
    89. 
    90. 
    91.//获取content->helder数据的方法。用来获取真正的数据  
    92.template<typename ValueType>  
    93.ValueType any_cast(const any& operand)  
    94.{  
    95.    assert( operand.type() == typeid(ValueType) );  
    96.    return static_cast<any::holder<ValueType> *>(operand.content)->held;  
    97.}  
    98. 
    99.//下代码是使用示例  
    100. 
    101.typedef std::list<any> list_any;  
    102. 
    103.void fill_list(list_any& la)  
    104.{      
    105.    la.push_back(10);//存放常数;调用了any的模板构造函数,下同  
    106.    la.push_back( std::string("我是string") );//存放字符串对象;注意la.push_back(“dyunze”)错误,因为会被当错字符串数组  
    107. 
    108.    char* p = "我是常量区字符串abc";  
    109.    la.push_back(p);//可以存放指针,但要注意指针的失效问题  
    110.}  
    111. 
    112.//根据类型进行显示  
    113.void show_list(list_any& la)  
    114.{  
    115.    list_any::iterator it;  
    116. 
    117.    for( it = la.begin(); it != la.end(); it++ )  
    118.    {     
    119. 
    120.        if( (*it).type() == typeid(int) )  
    121.            std::cout<<any_cast<int>(*it)<<std::endl;  
    122.        else if( (*it).type() == typeid(std::string) )  
    123.            std::cout<<any_cast<std::string>(*it).c_str()<<std::endl;  
    124.        else if( (*it).type() == typeid(char*) )  
    125.            std::cout<<any_cast<char*>(*it)<<std::endl;  
    126.    }  
    127.}  
    128. 
    129.int main()  
    130.{  
    131.    list_any la;  
    132.    fill_list(la);  
    133.    show_list(la);  
    134. 
    135.    return 0;  
    136.} 

     boost::any是一个很有趣的类,刚刚开始我还以为其就是一个variant类型,
    能够将任意类型值保存进去,能够以任意类型值读出来,不过我错了 :(
      boost::any的作者认为,所谓generic type有三个层面的解释方法:
      1.类似variant类型那样任意进行类型转换,可以保存一个(int)5进去,
        读一个(string)"5"出来。Win下面的VARIANT类型是以一个巨大的
        union实现的类似功能,使用灵活但效率较低
      2.区别对待包含值的类型,保存一个(int)5进去,不会被隐式转换为
        (string)'5'或者(double)5.0,这样效率较高且类型安全,
        不必担心ambiguous conversions
      3.对包含值类型不加区别,例如把所有保存的值强制转换为void *保存
        读取时再有程序员判断其类型。这样效率虽最高但无法保证类型安全
      boost::any就选择了第二层面的设计思路,它允许用户将任意类型值保存
    进一个any类型变量,但内部并不改变值的类型,并提供方法让用户在使用时
    主动/被动进行类型判断。

      在实现方面,boost::any使用两层内部类placeholder和holder保存
    实际类型的值。类placeholder只是一个接口,模板类holder是特定类型
    的实现。其中type()方法获取实际值类型,即typeid(ValueType);
    clone()方法获取值的拷贝return new holder(held);
      virtual const std::type_info & type() const
      virtual placeholder * clone() const
      其值的类型信息不象Win的VARIANT那样以专门的字段保存,
    而是通过模板参数形式静态保存。这样效率更高(仅在编译期),

    通用性更强(任何类型都可以,真正any)但灵活性不如VARIANT
      在进行拷贝构造/赋值/swap时,都直接将整个placeholder换掉,
    这样可以保证值类型的延续性。

      在使用方面,提供了主动/被动进行类型检测的方法。
      可以使用any::type()方法主动检测值类型
    bool is_int(const boost::any & operand)
    {
        return operand.type() == typeid(int);
    }
      也可以通过any_cast函数被动进行检测。此函数与C++中的*_cast
    系列关键字有相同的语法规范,尝试进行类型转换,如类型不匹配则对
    指针转换返回NULL,对引用转换抛出boost::bad_any_cast异常
      boost::any str = string("12345");
      try
      {
        cout << boost::any_cast<int>(str) << endl;
      }
      catch(boost::bad_any_cast e)
      {
        cerr << e.what() << endl;
      }


      在应用方面,any类型适合于类型不同但使用相关的值。如C++的...
    形式的函数参数本事不是类型安全的,可以通过vector<any>改造之
    然后在使用时检测类型是否匹配,如可改造printf为
      void safe_printf(const char *format, const vector<any>& params)
      {
        int index = 0;
        for(const char *pch = format; *pch; pch++)
        {
          switch(*pch)
          {
            case '%':
            {
              switch(*++pch)
              {
                case 'i':
                case 'd':
                {
                  if(params[index].type() == typeid(int) ||
                     params[index].type() == typeid(short))
                  {
                    ...
                  }
                  else
                    throw ...
                }
              }
            }
            case '\':
            {
              ...
            }
            default:
            {
              putchar(*pch);
            }
          }
        }
      }

    附:boost::any.hpp
    #ifndef BOOST_ANY_INCLUDED
    #define BOOST_ANY_INCLUDED

    // what:  variant type boost::any
    // who:   contributed by Kevlin Henney,
    //        with features contributed and bugs found by
    //        Ed Brey, Mark Rodgers, Peter Dimov, and James Curran
    // when:  July 2001
    // where: tested with BCC 5.5, MSVC 6.0, and g++ 2.95

    #include <algorithm>
    #include <typeinfo>

    #include "boost/config.hpp"

    namespace boost
    {
        class any
        {
        public: // structors

            any()
              : content(0)
            {
            }

            template<typename ValueType>
            any(const ValueType & value)
              : content(new holder<ValueType>(value))
            {
            }

            any(const any & other)
              : content(other.content ? other.content->clone() : 0)
            {
            }

            ~any()
            {
                delete content;
            }

        public: // modifiers

            any & swap(any & rhs)
            {
                std::swap(content, rhs.content);
                return *this;
            }

            template<typename ValueType>
            any & operator=(const ValueType & rhs)
            {
                any(rhs).swap(*this);
                return *this;
            }

            any & operator=(const any & rhs)
            {
                any(rhs).swap(*this);
                return *this;
            }

        public: // queries

            bool empty() const
            {
                return !content;
            }

            const std::type_info & type() const
            {
                return content ? content->type() : typeid(void);
            }

    #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
        private: // types
    #else
        public: // types (public so any_cast can be non-friend)
    #endif


            class placeholder
            {
            public: // structors
        
                virtual ~placeholder()
                {
                }

            public: // queries

                virtual const std::type_info & type() const = 0;

                virtual placeholder * clone() const = 0;
        
            };

            template<typename ValueType>
            class holder : public placeholder
            {
            public: // structors

                holder(const ValueType & value)
                  : held(value)
                {
                }

            public: // queries

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

                virtual placeholder * clone() const
                {

                    return new holder(held);
                }

            public: // representation

                ValueType held;

            };

    #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS

        private: // representation

            template<typename ValueType>
            friend ValueType * any_cast(any *);

    #else

        public: // representation (public so any_cast can be non-friend)

    #endif

            placeholder * content;

        };

        class bad_any_cast : public std::bad_cast
        {
        public:
            virtual const char * what() const throw()
            {
                return "boost::bad_any_cast: "
                       "failed conversion using boost::any_cast";
            }
        };

        template<typename ValueType>
        ValueType * any_cast(any * operand)
        {
            return operand && operand->type() == typeid(ValueType)
                        ? &static_cast<any::holder<ValueType> *>(operand->content)->held
                        : 0;
        }

        template<typename ValueType>
        const ValueType * any_cast(const any * operand)
        {
            return any_cast<ValueType>(const_cast<any *>(operand));
        }

        template<typename ValueType>
        ValueType any_cast(const any & operand)
        {
            const ValueType * result = any_cast<ValueType>(&operand);
            if(!result)
                throw bad_any_cast();
            return *result;
        }

    }

    // Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved.
    //
    // Permission to use, copy, modify, and distribute this software for any
    // purpose is hereby granted without fee, provided that this copyright and
    // permissions notice appear in all copies and derivatives.
    //
    // This software is provided "as is" without express or implied warranty.

    #endif

  • 相关阅读:
    .NET组件控件实例编程系列——4.多列下拉框和鼠标相关组件
    仿查询分析器的C#计算器——2.记号对象
    .NET组件控件实例编程系列——1.开篇
    仿查询分析器的C#计算器——1.初步分析
    WCF续写. IIS托管
    NhibernateReview
    文件路径,文件名,扩展名 常用操作
    Resharper.alt+enter
    textFieldShouldReturn 键盘无法消失 无法return的问题
    NHibernate原生SQL查询
  • 原文地址:https://www.cnblogs.com/kex1n/p/2013098.html
Copyright © 2011-2022 走看看