[C/C++]屬性的祕密——C++仿C#的屬性實做

一直以來,我都想爲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:本篇文章對應的是自動完成屬性的模仿,對於普通屬性的模仿,等待個人下一篇文章吧。
相關文章
相關標籤/搜索