如何限制对静态 public 成员的访问?

How to restrict access to static public members?

#include <cstdio>

struct Settings
{
  int i1, i2;
  Settings(int i1, int i2) : i1(i1), i2(i2) {}

  struct GeneralSettings
  {
    int gi1, gi2;
  } static gs;

  void do_something() const
  {
    printf("%d %d %d %d\n", i1, i2, gs.gi1, gs.gi2);
  }
};

Settings::GeneralSettings Settings::gs;

int main()
{
  Settings s1(0,1);
  Settings s2(1,0);

  s1.gs.gi1 = 1;         // I would like to access GeneralSettings like this only!
  Settings::gs.gi2 = 1;  // Can i prevent global access like this?

  s2.do_something();

  return 0;
}

请参阅上面的代码和评论。除了用 accessors/mutators 制作 Settings::gs private 之外,还有其他方法可以限制对 Settings::gs 的访问,以便只能通过 Settings 对象访问吗?事实上,任何函数都可以访问 Settings::gs,无论它是否可以访问 Settings 对象。 Settings::gs 本质上是一个全局对象。

Besides making Settings::gs private with accessors/mutators, are there other ways to restrict access to Settings::gs so that it can be accessed through Settings objects only?

不是真的(假设你想在 "accessed through" 时进行控制),这几乎就是 private 的要点以及访问器的用途;那就是为实例和私有静态数据提供对内部结构(可能已检查)的访问。

您可以改变语法以获得所需的语义(指针、引用、const 和非常量),但最终一旦成员变量是 public(或通过 public 成员访问,例如指针或引用),您放弃了一定程度的控制。这里的控制是在函数中实现的,是成员函数还是外部的utility/helper函数。

我不确定这里的意图。这取决于你所说的 "accessed through".

是什么意思

如果它正是您所追求的语法, 提供了解决方案。

如果控制力更强,您可以探索创建一个提供自定义 operator*()operator->() 的实用程序 class 的可行性,这样您就可以 "mimic"智能指针(在没有 "smart reference" 的情况下)。我不确定这是否会提供您想要的语法。

您也可以探索 pimpl pattern/idiom (an opaque pointer),它没有回答问题,但提供了一种替代设计,可以更好地解决您遇到的问题。

我仍然不明白这样做的意义,但您可以使用 public 对私有静态成员的引用(顺便说一句,我不建议这样做):

struct A {
private:
    struct B { int x, y; } static _b;

public:
    // c++11 initialization, prior you need to initialize b in the 
    // constructor of A
    B &b{_b};
};

A::B A::_b{0, 0};

然后:

int main() {
    A a1, a2;

    std::cout << a2.b.x << " ";
    a1.b.x = 4;
    std::cout << a2.b.x << std::endl;
}

输出:

0 4

正如@Niall 在评论中指出的那样,将引用作为属性将删除默认赋值运算符:

A a1, a2;
a2 = a1; // copy assignment is implicitly deleted

但是如果您需要它,您可以随时创建自己的,因为您不需要更新 b:

struct A {
private:
    struct B { int x, y; } static _b;
public:
    B &b{_b};
    A& operator= (A const&) {
        // ok, no need to update this->b!
        return *this;
    }
};

A a1, a2;
a1 = a2; // ok

不过,我可以想到几个选项,就像所有单例一样,这些选项不是线程安全的:

  1. 您可以只使用 public reference 来避免 accessors/mutators:
struct Settings {
private:
    struct GeneralSettings {
        int gi1, gi2;
    } static _gs;
public:
    int i1, i2;
    GeneralSettings& gs;
    Settings(int i1, int i2) : i1(i1), i2(i2), gs(_gs) {}

    void do_something() const {
        printf("%d %d %d %d\n", i1, i2, gs.gi1, gs.gi2);
    }
};
  1. 你实际上可以 make it a full on singleton,尽管这需要一个访问器,而不是一个修改器,并且它会花费你 const:
struct Settings {
    struct GeneralSettings {
        int gi1, gi2;
    };

    GeneralSettings& gs() {
        static GeneralSettings gs;

        return gs;
    }

    int i1, i2;
    Settings(int i1, int i2) : i1(i1), i2(i2) {}

    void do_something() {
        printf("%d %d %d %d\n", i1, i2, gs().gi1, gs().gi2);
    }
};