C++实现get和set

这个想法来自于C#,经常用wpf的话,会接触绑定。数据绑定的实现要点之一便是get与set方法,下面的片段展示了这个事请。如果您想直接带走代码,可以跳转到文章末尾。

namespace GetAndSet
{
    class Example
    {
        private string _x;
        public string x
        {
            get
            {
                Console.WriteLine("x 取得值");
                return _x;
            }
            set
            {
                Console.WriteLine("x 设置值");
                _x = value;
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Example test = new Example();

            test.x = "debug";

            Console.WriteLine("----------------");

            Console.WriteLine("test.x = " + test.x);
            Console.ReadKey();
        }
    }
}


如果你运行它,会得到:

这段代码的运行结果

是不是很有用。例如当我们尝试在一个程序里面造大轮子写GUI框架,上面的get和set方法将协助我们完成MVVM模型的要点之一——监听属性的改变情况。因此,我们需要它。但是很遗憾我们的C++好像没有这玩意....

但是退而求其次,可以使用内联函数来实现get与set,例如下面的这段C++代码:

class Example
{
public:
    Example() = default;
    ~Example() = default;
    inline void setX(int value)
    {
        x = value;
    }
    inline int getX()
    {
        return x;
    }
private:
    int x;
};

当我们需要设置或者访问x时,调用对应的内联方法即可。不过,把a = test.b + test.c写成a = test.get_b() + test.get_c(),怎么看都觉得很奇怪,因此,我们要漂亮的——既能有get和set,又像a = test.b + test.c一样简洁。

在我们写dll的时候会用到__declspec,在msdn上我们可以看到它可以完成包括但不限于dllimport、dllexport这些说明,其中的一个是property(点击这里查看),我们可以在简介中看到:编译器能把它替换成函数调用,也就是类似于C#里面的get与set。

这就好办了。测试一下:

class Example
{
public:
    Example() = default;
    ~Example() = default;
    __declspec(property(get = getx, put = putx)) int x;
    void putx(int value)
    {
        puts("set x");
        _x = value;
    }
    int getx()
    {
        puts("get x");
        return _x;
    }
private:
    int _x;
};
int main()
{
    Example test;
    test.x = 5;
    puts("------------");
    printf("test.x = %d\n", test.x);
    return 0;
}

运行,是否看到了和C#代码类似的结果呢?

通过指定put方法以及get方法,我们可以只指定get方法来实现read-only,当然也可以只指定put方法来实现write-only,两个都指定即可读可写:

同样的,我们把它变为宏定义,毕竟__declspec看着很大,对应的还有类似于C#的get、set关键字那样的宏:

#define  property_r(typ, name)   __declspec(property(get = __property_get_ ## name)) typ name;   \
                                 typedef typ __property_typ_ ## name
#define  property_w(typ, name)   __declspec(property(put = __property_set_ ## name)) typ name;   \
                                 typedef typ __property_typ_ ## name
#define  property_rw(typ, name)  __declspec(property(get = __property_get_ ## name, put = __property_set_ ## name)) typ name;   \
                                 typedef typ __property_typ_ ## name
#define  set(name)               void        __property_set_ ## name (__property_typ_ ## name value)
#define  get(name)               __property_typ_ ## name __property_get_ ## name ()
class Example
{
public:
    Example() = default;
    ~Example() = default;
    property_rw(int, x);
    set(x)
    {
        puts("set x");
        _x = value;
    }
    get(x)
    {
        puts("get x");
        return _x;
    }
private:
    int _x;
};
int main()
{
    Example test;
    test.x = 5;
    puts("------------");
    printf("test.x = %d\n", test.x);
    return 0;
}

规范起见你可以把宏定义名称全部改成大写的。测试运行一下,成功!

猜你喜欢

转载自blog.csdn.net/YanEast/article/details/105358391