【问题标题】:Is there a way in C++ to create 'super private' variables?C++ 中有没有办法创建“超级私有”变量?
【发布时间】:2011-11-26 19:33:14
【问题描述】:

我有一个 C++ 功能的想法,我想知道是否可以创建。

假设我希望“MyClass”中的私有变量只能由公共 getter 和 setter 这两个函数访问。也就是说,如果 MyClass 的另一个公共或私有函数试图获取或更改我的超级私有变量的值,我将得到一个编译错误。但是,getter 和 setter 行为正常。

有什么想法吗?

编辑 1:一个用例是让 getter/setter 执行错误检查或其他形式的逻辑。我什至不希望类本身直接接触变量。

编辑 2: 然后是这样的:

template <class T>
class State{
private:
    T state;

public:
    State()
    {
        state = 0;
    }

    T getState()
    {
        return state;
    }

    void setState(T state)
    {
        this->state = state;
    }
};

然后任何类都可以继承它并只能通过 getter/setter 访问“状态”。当然,如果不根据你想要的逻辑修改 getter 和 setter,这个类是没有用的。

【问题讨论】:

  • 你能提供一个用例吗?
  • 所以你可能做错了设计:如果该字段除了在类中被访问和存储之外没有更多的事情要做,那么它还不如在另一个类中。
  • 据我所知这是不可能的,尽管当你有与你的 getter/setter 相关联的逻辑时它会非常好。我一直只是试图记住使用 getter/setter,因为大多数时候你将成为类所有者。
  • 我觉得有必要创建一种语言来包含“超级隐私”这一令人敬畏的概念。它还将以“超级宣传”为特色。现在我只需要发明“Spidy Sense”编程范式。
  • @mikerobi 确保您还包括“任何宣传都是好的宣传”功能。

标签: c++ oop


【解决方案1】:

C++ 中可访问性的粒度是类。

所以如果你需要让一个变量只能被两个方法访问,你需要将变量和这两个方法移动到一个单独的类中,专门用于维护隐私..

【讨论】:

  • 我认为,这里应该使用术语"accessibility",而不是"visibility",因为术语visibility i> 在 C++ 中有不同的含义。
  • @Nawaz 谢谢。这么多的语言和这么多不同的名字给同样的东西!
  • @DavidHeffernan:我不认为其他语言使用术语visibility来表示accessibility;至少不是那些你可以隐藏名字的地方。
  • @DavidHeffernan:那么在Delphi中,没有名称隐藏的概念吧?
  • @Nawaz 隐藏是什么意思?
【解决方案2】:

您可以将变量包装在一个类中,并在那里将其设为私有并使用const T&amp; getter。然后将包含类的 get 和 set 成员函数声明为该包装器的朋友。现在,您将包装类保留为原始类中的成员。这应该可以实现您想要的,尽管它看起来很难维护并且不是很有用。

所以这里有一些虚拟实现来展示它是如何工作的(请注意,整个 new VeryPrivateWrapper 业务只是一种古怪的声明方式,unique_ptr 会更有帮助):

class VeryPrivateWrapper;

class Original {
  VeryPrivateWrapper* m_wrapper;

public:
  Original();
  // imagine that I remembered the rule of three here
  void set(int);
  void other();
};

// make this a template for more fun
class VeryPrivateWrapper {
  int m;
public:
  const int& get() const { return m; } 
  // !!!
  // the important bit 
  // !!!
  friend void Original::set(int);
};

Original::Original() : m_wrapper(new VeryPrivateWrapper) {}

void Original::set(int i) {
    m_wrapper->m = i;
}

void Original::other() {
  // this borks as we would like
  // m_wrapper->m = 23;
}

int main()
{
  Original o;
  o.set(3);
  return 0;
}

【讨论】:

  • 或者您可以只让 MyClass 从包装器继承(可能不公开),因此您不需要该友谊设置或使包装器成为成员。
  • @eran 然后其他成员函数将如何访问该成员?我以为这是一个要求。因为如果基类的变异 getter 可以被外部访问,那么它也可以被基类访问,对吧?
  • 我假设 getter 和 setter 可以是VeryPrivateWrapper 的一部分,所以Original 的所有成员函数都可以使用它们来获取或设置超级私有。如果 getter 和 setter 必须是 Original 的一部分,那么我猜你使用友谊的想法是唯一的选择。
  • @eran 我认为重要的部分是所有函数都默认为只读访问,只有 setter 函数应该能够具有写访问权限。
  • C++0x 支持匿名类吗?那可能会更干净一些。
【解决方案3】:

我相信这就是您所要求的。这是可取的吗?有些人会认为这是可憎的。

如果您决定使用它,您可能希望从宏中提取公共 Get 和 Set 并手动编写它们。

#define SUPER_PRIVATE(c,t,m) \
template <typename C, typename T> \
class SuperPrivate##m { \
    friend T& C::Get##m(); \
    friend void C::Set##m(const T&); \
    T value; \
}; \
public: \
    t& Get##m() { return m.value; } \
    void Set##m(const t& value) { m.value = value; } \
private: \
    SuperPrivate##m<c,t> m; 

class SomeClass
{
public:
    SomeClass()
    {
        SetX(42);
        SetY(58);
    }
    int DosomethingWithX() { return GetX() * 2; }
//  int DosomethingWithX2() { return X.value * 2; } // error
//  int DosomethingWithX3() { return X; } // error

    SUPER_PRIVATE(SomeClass, int, X);
    SUPER_PRIVATE(SomeClass, int, Y);
};

int main()
{
    SomeClass someObject;
    int x1 = someObject.GetX();
    int y1 = someObject.GetY();
    someObject.SetY(89);
    int y2 = someObject.GetY();
    int x2 = someObject.DosomethingWithX();

}

【讨论】:

  • 与我的尝试相比,我很想将这些宏称为可用性改进。
【解决方案4】:

我会给变量取一个非常丑陋的名字,给 getter/setter 取个好听的名字:

class Foo
{
private:
    int _hey_do_not_use_me_im_super_private_whatever;
public:
    int get_whatever() const
    {
        //extra logic
        return _hey_do_not_use_me_im_super_private_whatever;
    }
    void set_whatever(int we)
    {
        //extra logic
        _hey_do_not_use_me_im_super_private_whatever = we;
    }
};

解释超级私有意味着什么的评论将受到继承您代码的人的欢迎。

【讨论】:

  • 嗯,可以使用#define SUPERPRIVATE(x) superprivate_##x 之类的宏,但我个人认为它是多余的。
  • 我同意这样的宏是不必要的,但我指的是我自己的答案,它有一个更复杂的宏。我想这归结为使编译器能够捕获愚蠢的事情与相信人们不要做愚蠢的事情之间的区别。每次都输入 _hey_do_not_use_me_im_super_private_whatever 会很愚蠢,所以你的答案可能就足够了。另一方面,OP 确实要求提供会导致编译器错误的解决方案,但我仍然认为您的答案值得 +1。
猜你喜欢
  • 2017-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-05
相关资源
最近更新 更多