[C/C++]属性的秘密——C++仿C#的属性实作

自古美人都是妖i 提交于 2019-11-27 04:29:38
一直以来,我都想为C++引入C#里面定义的属性(Property),我尝试了几次:
读过上面三篇文章后就会发现,一直以来,我对属性的认识都是错误的,我的关注点全部放在了属性值的变化怎么被通知出去,而这在C#的属性定义中根本就是不被关注的。我们先看一下C#是怎么实现属性的。
首先我们写一个C#的普通类:
class A
{
    public double pp { get; set; }
    public double pv { get; protected set; }
    public double vp { protected get; set; }
}
然后再看反编译之后的IL代码:

可以看到一个属性被分解成三块:域(Field)、getter和setter、存取器(Accessor)。
Field是C#类的成员变量被定义的地方,对应C++也是类的成员变量定义(可访问性为:private);
getter和setter是C#类的成员函数,对应C++也是类的成员函数(可访问性为:private、protect或者public);
Accessor才是C#真正实现属性语法的地方(如下图所示),对应C++可以使用operator运算符实现。

如果仅仅考虑前两条,用C++很容易的就能使用宏展开模仿出来:
#define AutoProperty(ValueType, GetAccessor, SetAccessor, Variable)	private: ValueType Variable;\
GetAccessor: ValueType get##Variable() { return Variable; }\
SetAccessor: void set##Variable(ValueType newValue) { Variable = newValue; }
AutoProperty分为四个部分:ValueType是变量的类型;GetAccessor、 SetAccessor分别是getter和setter的可访问性;Variable是变量的名称。AutoProperty使用起来非常简单:
// 任务是否可以运行,只读属性
AutoProperty(bool, public, protected, CanRun);
但是当外部或子类使用如上定义的CanRun属性的时候,却只能通过getCanRun()和setCanRun()这一对成员函数,而不像C#那样简单。
下面我们考虑用C++模拟出C#的 Accessor实现的功能。
#include <functional>
using namespace std;

template<typename ValueType>
class Property
{
protected:
	typedef function<ValueType()> GetterType;
	GetterType getter;

	typedef function<void(ValueType)> SetterType;
	SetterType setter;

public:
	explicit Property(GetterType gt, SetterType st) : getter(gt), setter(st) {}
	operator ValueType() { return getter(); }
	Property& operator = (ValueType value) { setter(value); return *this; }
};

#define AutoProperty(ValueType, Variable)	\
public: Property<ValueType> Variable;\
private: ValueType var##Variable;\
private: ValueType get##Variable() { return var##Variable; }\
private: void set##Variable(ValueType newValue) { var##Variable = newValue; }\

#define AutoPropertyImpl(Variable, Value)	\
var##Variable(Value), Variable(bind(&A::get##Variable, this), bind(&A::set##Variable, this, placeholders::_1))

class A
{
public:
	// 任务是否可以运行,只读属性
	AutoProperty(bool, CanRun);

public:
	A() : AutoPropertyImpl(CanRun, true)
	{}
};



int main(int argc, char* argv[])
{
	A a;
	bool b = a.CanRun;
	a.CanRun = false;
	
	return 0;
}
上面的这一段代码是可以正确运行的,也就是说我成功了。

PS:本篇文章对应的是自动完成属性的模仿,对于普通属性的模仿,等待我的下一篇文章吧。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!