在上一篇文章中,我实现了C++的属性,但是总感觉哪里还是不对劲 ,嗯,对,是哪个this,属性初始化的时候VS会提示this在没初始化完毕就被使用,虽然我知道this在这个时候可以被使用,但是让编译器产生这么多的警告信息,看着也还是不爽。
今天突然跑出一个灵感来,何不用内部类试试呢?这样就可以隐藏this指针了。说干就干。下面就是成果了:
/*
* 属性实现需要的内部类
*/
#define variableproperty(ClassType, ValueType, GetAccessor, SetAccessor, Variable) \
public :\
class Variable##Property\
{\
GetAccessor:\
operator ValueType()\
{\
return Get##ClassType()->get##Variable();\
}\
SetAccessor:\
Variable##Property& operator = (ValueType value) \
{\
Get##ClassType()->set##Variable(value);\
return *this;\
}\
private:\
inline ClassType* Get##ClassType()\
{\
return ((ClassType*)((unsigned char*)this - offsetof(ClassType, Variable)));\
}\
}Variable;\
/*
* 自动实现的属性,在类内部自动实现原始成员变量定义及其访问函数:
* 原始变量为var##Variable,当属性为非可读写时,类内部可以访问它;
* 访问函数为get##Variable和set##Variable,这俩函数不能被外部访问.
*/
#define autoproperty(ClassType, ValueType, GetAccessor, SetAccessor, Variable) \
variableproperty(ClassType, ValueType, GetAccessor, SetAccessor, Variable) \
private: ValueType var##Variable;\
private: ValueType get##Variable() { return var##Variable; }\
private: void set##Variable(ValueType newValue) { var##Variable = newValue; }
#define autopropertyinit(Variable, InitValue) var##Variable(InitValue)
/*
* 一般(委托)属性,能够自定义getter和setter的名称.
*/
#define customproperty(ClassType, ValueType, GetAccessor, Getter, SetAccessor, Setter, Variable) \
variableproperty(ClassType, ValueType, GetAccessor, SetAccessor, Variable)\
private: ValueType get##Variable() { return Getter(); }\
private: void set##Variable(ValueType newValue) { Setter(newValue); }
/*
* 一般(委托)属性,使用固定格式的getter和setter:Variable##Getter/Variable##Setter.
*/
#define simpleproperty(ClassType, ValueType, GetAccessor, SetAccessor, Variable) \
customproperty(ClassType, ValueType, GetAccessor, Variable##Getter, SetAccessor, Variable##Setter, Variable)
使用起来也算不上复杂:
int gValue = 0;
int gOtherValue = 1;
struct CValue
{
int a;
short b;
}tCValue;
struct DValue
{
int a;
short b;
DValue(int t) : a(t), b(0) {}
DValue& operator= (DValue& t) { a = t.a; return *this; }
}tDValue(0);
class A
{
public:
// 基本数据类型
simpleproperty(A, int, public, public, a);
simpleproperty(A, double, public, public, b);
// 指针类型
autoproperty(A, int*, public, public, c);
autoproperty(A, void*, public, public, d);
// 引用类型
autoproperty(A, int&, public, public, e);
// 自定义类型
autoproperty(A, CValue, public, public, f);
autoproperty(A, DValue, public, public, g);
public:
A() : autopropertyinit(c, new int(1))
, autopropertyinit(d, nullptr)
, autopropertyinit(e, gValue)
, autopropertyinit(f, tCValue)
, autopropertyinit(g, tDValue)
{}
~A(){}
int aGetter()
{
return 0;
}
void aSetter(int thisV)
{
}
double bGetter()
{
return 1;
}
void bSetter(double thisV)
{
}
};
void testProperty()
{
tCValue.a = 10;
tCValue.b = 9;
A a;
a.a = 9;
a.b = 7.10;
a.c = new int(2);
a.d = new int(3);
// 引用类型,只能传递引用?
a.e = gOtherValue;
tCValue.a = 9;
tCValue.b = 10;
a.f = tCValue;
a.g = DValue(9);
}
最后说一下,为什么要使用 autopropertyinit吧?本来可以让内部类实现一个带参数的构造函数,但是如果属性是自定义类型或者引用类型,就需要对原始变量重新初始化一次,反而麻烦了,不如再加个宏,只针对原始值进行初始化反而简单。
大家可以比较一下前后两种方法的优劣:
第一种用委托实现的方式总体来说要占用更多的存储空间;
第二种用内部类实现的方式总体来说会造成大量的内部类。
... ...