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

时间:2023-01-15 15:12:51

I have a member variable, enabled_m, whose value is dependent on a number of variables. Since these invariants should be maintained by the class, I want it to be private:

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

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;
};

Which works, but really my intent is to require a user of foo_t to go through the class to modify enabled_m. If the user wants to just read enabled_m, that should be an allowable operation:

哪个有效,但我的意图是要求foo_t的用户通过该类来修改enabled_m。如果用户想要只读取enabled_m,那应该是允许的操作:

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

Is there a way to make enabled_m public for const operations and private for non-const operations, all without having to require a user go through accessor routines?

有没有办法使const_m为const操作公开,私有用于非const操作,所有这些都不需要用户通过访问器例程?

3 个解决方案

#1


9  

No, there's no way to restrict modification only to members. private restricts all access to the name; const prevents modification everywhere.

不,没有办法只限制成员的修改。 private限制对名称的所有访问; const阻止了各地的修改。

There are some grotesque alternatives (like a const reference, or use of const_cast), but the accessor function is the simplest and most idiomatic way to do this. If it's inline, as in your example, then its use should be as efficient as direct access.

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

#2


10  

Most engineers will prefer that you use accessor methods, but if you really want a hack-around, you could do something like this:

大多数工程师都希望你使用访问器方法,但如果你真的想要一个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;
    }
};

#3


5  

A great deal here depends upon the intent behind exposing the enabled state, but my general advice would be to avoid exposing it at all.

这里有很多取决于暴露启用状态背后的意图,但我的一般建议是避免暴露它。

The usual use of your is_enabled would be something like:

通常使用is_enabled将是这样的:

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

In my opinion, it's nearly always better to just call the set_this, and (if the client cares) have it return a value to indicate whether that succeeded, so the client code becomes something like:

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

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

Although this may seem like a trivial difference when you start to do multi-threaded programming (for one major example) the difference becomes absolutely critical. In particular, the first code that tests the enabled state, then attempts to set the value is subject to a race condition--the enabled state may change between the call to is_enabled and the call to set_this.

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

To make a long story short, this is usually a poor design. Just don't do it.

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

#1


9  

No, there's no way to restrict modification only to members. private restricts all access to the name; const prevents modification everywhere.

不,没有办法只限制成员的修改。 private限制对名称的所有访问; const阻止了各地的修改。

There are some grotesque alternatives (like a const reference, or use of const_cast), but the accessor function is the simplest and most idiomatic way to do this. If it's inline, as in your example, then its use should be as efficient as direct access.

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

#2


10  

Most engineers will prefer that you use accessor methods, but if you really want a hack-around, you could do something like this:

大多数工程师都希望你使用访问器方法,但如果你真的想要一个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;
    }
};

#3


5  

A great deal here depends upon the intent behind exposing the enabled state, but my general advice would be to avoid exposing it at all.

这里有很多取决于暴露启用状态背后的意图,但我的一般建议是避免暴露它。

The usual use of your is_enabled would be something like:

通常使用is_enabled将是这样的:

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

In my opinion, it's nearly always better to just call the set_this, and (if the client cares) have it return a value to indicate whether that succeeded, so the client code becomes something like:

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

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

Although this may seem like a trivial difference when you start to do multi-threaded programming (for one major example) the difference becomes absolutely critical. In particular, the first code that tests the enabled state, then attempts to set the value is subject to a race condition--the enabled state may change between the call to is_enabled and the call to set_this.

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

To make a long story short, this is usually a poor design. Just don't do it.

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