boost::Any架构

boostany解析

我们描述一种事物,就必须要有这种事物特定的属性和方法,不同的事物,它们的属性和方法都是不一样的,这个对于单个事物来说还比较好描述,一个事物一个实例,但是但出现批量的时候,事物过多并且还有很多种未知的事物可能出现,这个时候考虑到框架的可适应性,很多人都会很纠结。

假设类型Aclass A。我们用一个数组vector去存放这样的一组数据类型,然后我们知道这个vector中的每一个数据都是类型A的,这样我们就可以去方便的操作它,添加、删除、获得其中一项调用其接口、为其分配内存等等,这些操作的前提都是我们确定的知道我们的vector中存放的就是A,这里万一有一天需求变更,除了A之外还要再次存放数据B,这个时候就不是很好办了,有人就会说我把两个对象抽象一下,并且我们存放的是对象的指针,这里我们就不能是Vector<A>,而要变成vector<AB *>,其中ABAB公用的父类,貌似能够解决这个问题了,但是这种结局方式有几个很大的问题,首先可扩展性不是很好,万一需求又来了,出现了一个新的类C也要存放到这个列表中,然后你又会花时间想办法在抽象一个更大的抽象类ABC,整个代码都要调整,这样工作量也很大。另外一个问题就是,ABC本身就不是具有共性的一类东西,抽象的太厉害,父类就没有什么东西了,那么我们ABC三个子类各自特定的属性和方法就很难去调用了。这样就出现了这样的一个问题。

我们知道不管是什么类,放在内存里面我们用指针就可以去访问,不管你的类的大小或者派生层次等,所有类的指针都是一样的,32位平台就是一个32的地址数据,64位的平台就是一个64位的数据,这样来说最抽象的东西就是Void *指针,这样就抽想到极致了,我们就不会因为又来了一个D类而想办法去抽象D的一些属性,直接一个vector<void *>来表述我们存放的数据,这样无论数据类型有多少,我以不变应万变。

但是上面的做法会抹杀所有具体类型的特性,就好像男人和女人都是人,那还区分男人和女人干什么。所以这里通过void *来抽象做的太绝对了,又没有一种方式既可以做到包容,又可以做到不抹杀特性。这里我们的Any就出现了。

我们构建一个类叫做Any,可以封装所有的类,现有的或者将来会有的都可以封装在里面。我们知道类有一个最大的公用特点就是都要放在内存,凡在内存就会有指针,所以Any的一个重要的内容就是封装指针,其次虽然都是人,但也会有男人和女人、中国人和美国人之分,这里我们要封装的第二种东西就是特性,中国人是黄皮肤,美国人是白皮肤,这样我们要封装一个表示特性的参数,这个就是一个Type。这样我们在调用者和实际被调用者之间加入了一层过渡层,可以理解为门面模式。

Any

{

Void*

TypeId

}

上面的就是我们Any做的事情。在boost中,这个Any充分的利用了模板的一些特性来实现。下面简单的分析源码。

首先我们要存放这个最关键的两项数据:

class placeholder 

        {

        public: // structors

    

            virtual ~placeholder()

            {

            }

        public: // queries

            virtual const std::type_info& getType() const = 0;  //得到类型

            virtual placeholder * clone() const = 0;  //可以复制

    

virtual void writeToStream(std::ostream& o) = 0;  //输出流 这个方法其实可以不要

        };

然后按照这个接口我们来实现我们的模板:

template<typename ValueType>

        class holder : public placeholder

        {

        public: // structors

            holder(const ValueType & value)  //构造函数里面要有类型输入

              : held(value)

            {

            }

        public: // queries

            virtual const std::type_info & getType() const  返回数据类型

            {

                return typeid(ValueType);

            }

            virtual placeholder * clone() const  //更具类型自我复制

            {

                return OGRE_NEW_T(holder, MEMCATEGORY_GENERAL)(held);

            }

virtual void writeToStream(std::ostream& o)  //输出

{

o << held;

}

        public: // representation

            ValueType held;

        };

然后我们看看Any的实现:

我们的Any类中只有一个成员就是

 placeholder * mContent;   这里是以指针的方式来存放,通过它首先可以得到我们的数据类型,然后也可以得到指针地址,其实相当于在原始把void *变成了placeholder *两个都是最抽象的指针,不过后者还可以得到指针指向内容的类型。

这样我们在给这个Any类一些其他的方法,让她可以方便的使用。

class Any 

    {

    public: // constructors

        Any()

          : mContent(0)  //指向一片虚无

        {

        }

        template<typename ValueType>  //构造函数一定要显示的调用 调用的时候还有有具体类型。然后我们就会new出这样的一个对象

        explicit Any(const ValueType & value)

          : mContent(OGRE_NEW_T(holder<ValueType>, MEMCATEGORY_GENERAL)(value))

        {

        }

        Any(const Any & other)  //可以从其他地方克隆过来

          : mContent(other.mContent ? other.mContent->clone() : 0)

        {

        }

        virtual ~Any()

        {

            destroy();

        }

    public: // modifiers

        Any& swap(Any & rhs) //交换一下,你只想A我来指向B,交换包括指针和类型的同时交换。

        {

            std::swap(mContent, rhs.mContent);

            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;

        }

后面略。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值