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

    boost::any用法示例:

    #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,类型转换的功能。

    #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源代码

  • 相关阅读:
    android模拟器加速
    QtEmbedded鼠标驱动流程分析(上)
    QML Tutorial 1 Basic Types
    android 版本
    【转】右键菜单大揭密
    【转】设置右键显示/隐藏系统文件
    【转】自己做的登录界面五款正常尺寸+一款宽屏【手把手教You如何制作登录界面】
    【转】如何添加鼠标右键菜单里的快捷图标
    【转】鼠标右键菜单设置大全
    【技术贴】我的文档不见了,我的文档消失了,我的电脑没有我的文档的解决办法。
  • 原文地址:https://www.cnblogs.com/qiangxia/p/4578667.html
Copyright © 2011-2022 走看看