【问题标题】:How to restrict access to static public members?如何限制对静态公共成员的访问?
【发布时间】:2016-04-26 10:41:59
【问题描述】:
#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;
}

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

【问题讨论】:

  • 这样做有什么意义?
  • @Holt:避免将Settings::GeneralSettings 暴露给任何地方的每个函数。
  • 你现在已经在 Settings 结构中暴露了所有东西,为什么你只关心静态成员?

标签: c++ class struct static-members


【解决方案1】:

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

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

【讨论】:

  • 有趣的选择。 B&amp; b{_b}; 有效地使 A 不可赋值(赋值运算符被隐式删除)。您可以将其设为指针B* b{&amp;_b};,但这反过来又会遇到可以设置为nullptr 的缺点(但至少限于当前对象实例)。可以编写/使用包装器来限制或允许公共成员 (b) 所需的语义(例如 std::reference_wrapper,但最终仍会通过某种功能(例如 reference_wrapper::get())行使控制权。
  • @Niall B&amp; b{_b} 删除了默认赋值运算符,但它不会阻止您在需要时创建自己的运算符(因为在这种情况下您不需要分配给 b应该没问题)。
  • 确实如此。为了清楚起见,也许将其添加到答案中。
【解决方案2】:

除了使Settings::gs private 带有访问器/修改器之外,还有其他方法可以限制对Settings::gs 的访问,使其只能通过Settings 对象访问?

并非如此(假设您在“通过”访问时想要控制),这几乎是private 的重点以及访问器的用途;即提供对实例和私有静态数据的内部访问(可能已检查)。

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

我不确定这里的意图。这取决于您所说的“通过访问”是什么意思。

如果它只是您所追求的语法,this answer (for the current question) 会提供解决方案。

如果是更多控制,您可以探索创建提供自定义operator*()operator-&gt;() 的实用程序类的可行性,因此您可以“模仿”智能指针(在没有“智能引用”的情况下) )。我不确定这是否会提供您所追求的语法。

您也可以探索pimpl 模式/习语(opaque pointer),它不会回答问题,但会提供一种替代设计,可以更好地解决您遇到的问题。

【讨论】:

    【解决方案3】:

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

    1. 您可以只使用 public reference 来避免访问器/突变器:
    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,虽然这需要一个访问器,虽然不是一个mutator,而且它会花费你你的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);
        }
    };
    

    【讨论】:

    • @Downvoter 请解释一下?我认为这是一个很好的答案
    猜你喜欢
    • 2013-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-10
    • 1970-01-01
    • 1970-01-01
    • 2015-02-10
    • 2011-04-18
    相关资源
    最近更新 更多