我想增强C ++类的成员,以便从/向它们的赋值导致调用自定义getter / setter。
像
class Class
{
public:
int Member;
void SetMember(int Value); // TBD
int GetMember(); // TBD
}
和
Class Instance;
Instance.Member= 3; // Causes a call to SetMember(3);
int Data= Instance.Member; // Causes a call to GetMember();
我找到了一种方法来强制对成员赋值进行函数调用,方法是将成员类型转换为包含私有值的类,并重载强制转换的运算符和赋值运算符以进行写入。
class WrapInt
{
public:
operator int() const { return Value; }
void operator=(const int Assign) { Value= Assign; }
private:
int Value;
}
这是有效的,但是以通用方式,我不能为每个成员自定义getter / setter,而只能为每种数据类型定制。
您是否看到了一种改进方法,以便为不同类型的成员编写不同的访问者?
更新
我现在找到了满足我需求的解决方案。需要特殊setter的成员使用知道托管类的类来定义:
template<class Parent> class WrapInt
{
public:
int operator=(const int Value) { (This->*Setter)(Value); return Value; }
operator int() { return Value; }
private:
int Value;
Parent* This;
void (Parent::*Setter)(int Value);
friend Parent;
};
分配这样的成员会调用赋值运算符,该运算符通过指向主类方法的指针调用普通的setter函数。 Get操作是通过强制转换操作符实现的,该操作符只返回成员值(该方案可能会增强以支持自定义getter,但我并不需要)。
这是非常昂贵的,因为每个成员都需要额外的This
指向类实例和指向setter的指针;这些需要在类构造函数中初始化(如果没有,则保证崩溃)。
所以这需要在类编写器方面做一些努力(在构造函数中初始化),但是然后分配给成员会自动调用setter,如我所愿。
class Class
{
public:
Class();
WrapInt<Class> Member;
private:
void SetMember(int Value); // TBD
}
Class::Class() { Member.This= this; Member.Setter= &Class::SetMember; }
在用户一侧,
Class Instance;
Instance.Member= 3; // Calls the setter SetMember
cout << Instance.Member;
是的。
答案 0 :(得分:0)
代码的修改版本:
class WrapInt
{
public:
WrapInt(std::function<int()> getter, std::function<void(int)> setter) :
getter(getter),
setter(setter)
{}
WrapInt(const WrapInt&) = delete;
WrapInt& operator =(const WrapInt&) = delete;
operator int() const { return getter(); }
void operator=(int value) { setter(value); }
private:
std::function<int()> getter;
std::function<void(int)> setter;
};
class Class
{
public:
Class() : Member([this](){ return this->GetMember();},
[this](int value) {SetMember(value); })
{}
WrapInt Member;
void SetMember(int Value); // TBD
int GetMember(); // TBD
};
答案 1 :(得分:0)
您可以使您的班级WrapInt
可修改。
选项1:在运行时,使用函数对象
class WrapInt
{
public:
operator int() const { return Value; }
void operator=(const int Assign)
{
assign_callback(Assign);
Value = Assign;
}
private:
int Value;
std::function<void (int)> assign_callback;
}
在此变体中,您必须在包含类的构造函数中分配正确的回调:
class Container
{
WrapInt a, b, c;
Container ()
{
a.assign_callback = ...;
b.assign_callback = ...;
c.assign_callback = ...;
}
}
选项2:在编译时,使用继承
class WrapInt
{
public:
operator int() const { return Value; }
void operator=(const int Assign)
{
assign_callback(Assign);
Value = Assign;
}
private:
int Value;
virtual void assign_callback(int) = 0;
}
在此变体中,您将在包含类的类主体中多次从WrapInt继承
class Container
{
class WrapIntA : public WrapInt {
void assign_callback() { ... };
} a;
class WrapIntB : public WrapInt {
void assign_callback() { ... };
} b;
class WrapIntC : public WrapInt {
void assign_callback() { ... };
} c;
}
答案 2 :(得分:0)
不要与语言作斗争:C ++不支持对函数的get / set绑定。你只需要容忍
Instance.Member() = 3;
和
int Data = Instance.Member();
您可以通过提供返回const
引用的Member()
函数const
和返回非const
版本的非const
版本来提供参考。
对C ++的一个批评是你需要编写的样板量,特别是如果你需要为你的类中的每个成员变量都需要它。但实际上,在这一点上,你几乎完全避免了封装:除非你的函数进行一致性检查,否则你也可以让成员public
。