C++中的property库的设计与实现过程(二)——如何为属性指定get_和set_函数?

好了,现在就开始真正实现这个property库。我不打算一开始就把自己现有实现全盘托出,我希望记录整个设计的过程,这样,说不定在写这些文章的同时我还能找到进一步优化这个库的方法。
首先来想想,这个类应该怎么定义才好。
设想有这么一个类Sample,其中有一个属性X,那么代码可能要写成这样:

class Sample
{
   
int x_;  // Is it necessary?

public:
   
int get_X() const
   
{
       
return x_;
    }


   
int set_X(int value)
   
{
        x_
= value;
       
return x_;
    }


    rdxLib::property_bag
</* How to design? */> X;

    Sample()
        : X(
/* How to initialize? */)
   
{
    }

}
;

这当然是仿造C#的属性写的C++代码,并不一定合理,但至少反映了一些现实:property_bag类(不叫property是因为怕与关键字冲突)必须是一个模板类,因为它是一个容器;必定有一个地方要把X和get_X与set_X关联起来,这个理由是显然的。

我首先想到的是在模板参数中指定get_X和set_X,就像这么定义:

namespace rdxLib {
    template
<typename Parent, typename Type, Type (Parent::*Get)()const, Type (Parent::*Set)(Type)>
   
class property_bag
   
{
        typedef Type (Parent::
*GetFunc)() const;
        typedef Type (Parent::
*SetFunc)(Type);

        GetFunc get_;
        SetFunc set_;

   
public:
        property_bag()
            : get_(Get)
            , set_(Set)
       
{
        }

    }
;
}

很酷不是么?刚写完之后有一种特别的成就感,嗯,C++ trick呢!
不过马上我就意识到问题了:
get 和set函数的返回值或参数的类型是Type明显不合理,如果是对象的话,应该使用Type &或const Type&才对。很不幸的是,从类型的角度来说,Type & (Parent::*Get)() const 与 Type (Parent::*Get)() const 是完全不兼容的!所以无论多酷,这都不能算是一种好方法!
于是我做了一些修改:

namespace rdxLib {
    template
<typename Parent, typename Type>
   
class property_bag
   
{
        typedef property_bag
<Parent, Type> MyType;
        typedef
const Type & (Parent::*Get)() const;
        typedef Type
& (Parent::*Set)(const Type &);

        Get getFunction_;
        Set setFunction_;

   
public:
        property_bag(Get get, Set set)
            : getFunction_(get)
            , setFunction_(set)
       
{
        }

    }
;
}

长长的模板参数不见了,而get和set函数的初始化位置改到构造函数中去,显得更加简洁。等等,成员函数的指针怎么调用呢?我需要一个Parent指针!所以还应该改改,加上Parent指针才对:

namespace rdxLib {
    template <typename Parent, typename Type
>
   
class property_bag
   
{
        typedef property_bag
<Parent, Type> MyType;
        typedef
const Type & (Parent::*Get)() const;
        typedef Type
& (Parent::*Set)(const Type &);

        Parent
* parent_;
        Get getFunction_;
        Set setFunction_;

   
public:
        property_bag(Parent *parent, Get get, Set set)
            : parent_(parent)
            , getFunction_(get)
            , setFunction_(set)
       
{
        }

    }
;
}

完了么?远着呢!很显然,int与复杂类相比,get和set函数的声明肯定不同,我需要为所有的基础类型和指针类型、引用类型偏特化才行,所以这样的类肯定会有很多问题。
不过偏特化并不一定现在就要引入,因为麻烦,需要写一大堆一大堆的代码,首先还是针对int做一个简单的特化来看看效果好了,实现功能是第一位的呢。对int的特化代码就不贴了,仅仅是改了改typedef。

至此为止,get和set函数的大体位置就可以确定了。

相关阅读

有话想说?请留下评论吧~~如果喜欢我的blog,欢迎订阅~~

评论

还没有任何评论。

留下评论

(必需)

(必需)