是否可以仅为const操作指定一个私有成员变量public?

fbr*_*eto 4 c++ const member-variables c++11

我有一个成员变量,enabled_m其值取决于许多变量.由于这些不变量应该由类维护,我希望它是private:

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;
};
Run Code Online (Sandbox Code Playgroud)

哪个有效,但我的意图是要求用户foo_t通过课程进行修改 enabled_m.如果用户想要阅读 enabled_m,那应该是允许的操作:

bool my_enabled = foo.enabled_m; // OK
foo.enabled_m = my_enabled; // Error: enabled_m is private
Run Code Online (Sandbox Code Playgroud)

有没有一种方法,使enabled_m publicconst操作和private对非const业务,所有这些都无需要求用户去通过访问程序?

iwo*_*olf 10

大多数工程师都希望你使用访问器方法,但如果你真的想要一个hack-around,你可以这样做:

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;
    }
};
Run Code Online (Sandbox Code Playgroud)

  • 是的,@ MikeSeymour,我想这就是你把这种方法放在"怪诞"组中的原因.+1给你的答案. (3认同)
  • 您需要一个非默认的复制构造函数来正确初始化引用; 如果要允许赋值,则使用非默认赋值运算符. (2认同)

Mik*_*our 9

不,没有办法只限制成员修改.private限制对名称的所有访问; const防止到处修改.

有一些奇怪的替代品(如const参考或使用const_cast),但访问器功能是最简单和最惯用的方式.如果它是内联的,如在您的示例中,那么它的使用应该与直接访问一样有效.

  • @Christophe:添加引用成员会破坏复制语义:默认的复制构造函数会为您提供对错误对象的引用.我称之为怪诞.使用`const_cast`来修改`const`成员是UB,这无疑是怪诞的. (2认同)
  • @fbrereto,不,因为如果它被声明为`const`那么就没有办法在访问器中修改它. (2认同)

Jer*_*fin 5

这里的一个很大取决于背后暴露启用状态的意图,我一般建议是避免将其暴露在所有.

通常使用你的is_enabled东西是这样的:

if (f.is_enabled())
    f.set_this(whatever);
Run Code Online (Sandbox Code Playgroud)

在我看来,调用它几乎总是更好set_this,并且(如果客户端关心)让它返回一个值来指示是否成功,所以客户端代码变成如下:

if (!f.set_this(whatever))
   // deal with error
Run Code Online (Sandbox Code Playgroud)

虽然当你开始进行多线程编程时,这似乎是一个微不足道的差异(对于一个主要的例子),差异变得绝对至关重要.特别是,测试启用状态的第一个代码然后尝试设置值受竞争条件的影响 - enabled状态可能在调用is_enabled和调用之间发生变化set_this.

长话短说,这通常是一个糟糕的设计.只是不要这样做.