2014-10-31 31 views
4

我有一个成员变量,enabled_m,它的值取决于许多变量。由于这些不变量应当由类保持下去,我希望它是private是否可以指定仅用于const操作的公共成员变量public?

class foo_t 
{ 
public: 
    void set_this(...); // may affect enabled_m 
    void set_that(...); // may affect enabled_m 
    void set_the_other_thing(...); // may affect enabled_m 

    bool is_enabled() const { return enabled_m; } 

private: 
    bool enabled_m; 
}; 

其中一期工程,但实际上我的意图是要求的foo_t用户通过类去修改enabled_m。如果用户希望只阅读enabled_m,这应该是允许的操作:

bool my_enabled = foo.enabled_m; // OK 
foo.enabled_m = my_enabled; // Error: enabled_m is private 

有没有一种方法,使enabled_mpublicconst操作和private用于非const运营,而不必要求用户通过访问器例程?

+5

使用getter函数有什么问题?如果你关心的是效率问题,那么返回'const bool&'的'inline'函数可能会编译成与直接成员访问相同的内容。 – dlf 2014-10-31 17:15:53

+0

你或许可以创建一些代理对象,指向你的“真正的”布尔 - 但它真的值得吗?吸气剂是最流行和最干净的解决方案。 – 2014-10-31 17:17:26

+0

除了@ dlf的担忧之外,我认为即使可以这样做,界面二元性也会让事情变得混乱。 – Borgleader 2014-10-31 17:17:40

回答

9

不,没有办法限制仅对会员进行修改。 private限制对名称的所有访问; const可以防止到处修改。

有一些怪诞的选择(如const参考或使用const_cast),但访问器功能是最简单和最习惯的方式来做到这一点。如果它是内联的,就像你的例子那样,那么它的使用应该和直接访问一样高效。

+0

这也是我的推理路线 - 只是想确定我没有错过任何东西。 – fbrereto 2014-10-31 17:20:10

+0

“怪诞”一词似乎过度优化了一个有效的构造。然而,我认为最好不要这样去做,因为它可能会阻碍这个类的未来发展(f.ex将进行懒惰评估,或者在派生类中做出不同的决定) – Christophe 2014-10-31 18:10:05

+2

@Christophe:添加一个引用成员会破坏副本语义:默认的拷贝构造函数会给你一个对错误对象的引用。我会称之为怪诞。使用'const_cast'来修改'const'成员是UB,这是无可争议的怪诞。 – 2014-10-31 18:18:20

10

大多数工程师会偏好使用存取方法,但如果你真的想要,围绕破解一个,你可以做这样的事情:

class AccessControl 
{ 
private: 
    int dontModifyMeBro; 
public: 
    const int& rDontModifyMeBro; 
    AccessControl(int theInt): dontModifyMeBro(theInt), rDontModifyMeBro(dontModifyMeBro) 
    {} 

    // The default copy constructor would give a reference to the wrong variable. 
    // Either delete it, or provide a correct version. 
    AccessControl(AccessControl const & other): 
     dontModifyMeBro(other.rDontModifyMeBro), 
     rDontModifyMeBro(dontModifyMeBro) 
    {} 

    // The reference member deletes the default assignment operator. 
    // Either leave it deleted, or provide a correct version. 
    AccessControl & operator=(AccessControl const & other) { 
     dontModifyMeBro = other.dontModifyMeBro; 
    } 
}; 
+2

您需要一个非默认的拷贝构造函数来正确地初始化引用;如果您想允许分配,则使用非默认赋值运算符。 – 2014-10-31 17:24:36

+3

是的,@MikeSeymour,我想这就是为什么你把这种方法放在“怪诞”组中。 +1给你的答案。 – iwolf 2014-10-31 17:28:03

5

了大量这里取决于意图的背后暴露出启用状态,我的一般建议是避免暴露它在所有

通常使用的is_enabled会是这样的:

if (f.is_enabled()) 
    f.set_this(whatever); 

在我看来,它几乎总是最好只调用set_this,以及(如果客户关心)有它返回一个值来表示不管是成功的,所以客户端代码变得像:

if (!f.set_this(whatever)) 
    // deal with error 

虽然这可能看起来是一个微不足道的差异,当你开始做多线程编程(一个主要例子)的差异变得absolutel Ÿ关键。特别是,测试启用状态的第一个代码,然后尝试设置该值受竞争条件的影响 - enabled状态可能会在呼叫is_enabled和呼叫set_this之间发生变化。要长话短说,这通常是一个糟糕的设计。只是不要这样做。

相关问题