这个想法来自于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;
}
规范起见你可以把宏定义名称全部改成大写的。测试运行一下,成功!