出于好奇,我想知道以下课程:
class Number
{
public:
double value;
double square;
};
可以更改(使用自定义类型,代理,...),例如更改Number :: value将触发Number :: square的计算,不使用访问器(如Number: :的setValue())
我认为自定义类型而不是double可能会重载operator =,从而拦截值的赋值(顺便说一下,这是代理模式吗?)。但是,我需要一种方法来通知类Number的实例,事情发生了变化。
我确信C ++足够强大,但也许我错了。
答案 0 :(得分:3)
在推测时,拦截对成员的分配涉及使用具有用户定义的赋值运算符的类型。
我已经将这种技术用于调试 spaghetti系统。一旦明确了作业的来源,发生的事情顺序或者之后的任何信息,我们的想法就是删除拦截。因为它有一些严重的成本:
调试版本中的调用开销。
不完美转换回原始类型,即不会自动处理所有使用方案。
排除用户代码获取参考或指向该项目的指针。
为了让分配自动更新其他项目,您需要指向该项目或包含结构的指针或引用。这引入了进一步的空间和执行开销。因此,除了调试场景之外,最好使用普通的setter函数,而不是隐式赋值拦截:通常, explicit是好的,隐式是坏的。
附录:我忘了评论问题中的特定使用方案,这可能是“真正的”问题?
无论如何,当一个值B由值A确定时,通常的解决方案是提供获得B的函数,而不是存储B值。如果存储了B,那么可以修改它的用户代码不应该访问它,因为这很容易引起不正确的修改。所以它应该是protected
或private
(最好是后者),并且应该使用代码提供一个访问函数。
const
对象上进行更新,因此应将存储的值声明为mutable
。
总结一下,当B作为数据项的存储和更新是为了提高效率时,B项只是该值的缓存,那么
B应为非public
和mutable
,
应该有一个布尔值或其他方法来确定是否需要更新,
应该有一个公共访问者功能。
这些问题与隐式赋值拦截问题有很大不同。 ; - )
答案 1 :(得分:2)
您正在做的事情听起来像是'observer' or 'listener' pattern in C++
的一个实例你只需要一个代码钩子来调用'notifyObservers' - 正如你所说的那样可能是一个重载的运算符=(它自然适合于一个setter方法,但你不想拥有这些)
答案 2 :(得分:2)
您的代理理念当然可行:
class Number;
struct Proxy {
Proxy(Number *parent) : parent(parent) {}
Proxy &operator=(double d);
operator double() { return value; }
private:
Number *parent;
double value;
};
class Number
{
public:
Proxy value;
double square;
Number() : value(this) {}
// I imagine you want a double ctor too
};
Proxy &Proxy::operator=(double d) {
value = d;
parent->square = d * d;
return *this;
}
您仍然可能会有人分配给square
。您可以添加另一个代理,但所有这些的麻烦是为什么在C ++中使用访问器函数而不是对强制不变量的类的直接属性访问是惯用的。