公共静态const变量是否打破了封装意识形态?

时间:2011-05-07 16:31:43

标签: c++ encapsulation

我似乎总是很难决定应该是staticconst的类中的值是公共的还是私有的,并且使用静态公共方法进行访问。

class DeepThought
{
public:
    static const int TheAnswer = 42;
};

class DeepThought
{
public:
    static int GetTheAnswer() { return TheAnswer; }
private:
    static const int TheAnswer = 42;
};

希望以第一种方式做到这一点,但在我内心的某个地方感觉它破坏了封装,即使它是一个恒定值。第二种方式似乎并没有真正为表添加任何东西,但不必要地使代码混乱。

所以我问,这两种选择都存在根本错误吗?如果是,那又是什么?

6 个答案:

答案 0 :(得分:5)

它们在语义上不相同。首选,因为它产生一个整数常量表达式,可用于数组边界,非类型模板参数,case表达式等。

int a[DeepThought::TheAnswer];      // ok
int b[DeepThought::GetTheAnswer()]; // broken

答案 1 :(得分:4)

纯粹从理论上讲,第二种选择是更正确的。在实际意义上,我同意你的看法 - 用getter函数包装常量值是没用的,无论如何都会被编译器删除。

根据我的经验,有时候更简单的方法会更好,即使它在某种程度上违反了OOP。

最后一点 - 我们过去常常使用枚举:

enum CONSTS
{
    TheAnswer = 42,
};

答案 2 :(得分:4)

你应该考虑为什么 OOP“意识形态”说不暴露变量,只暴露出来。通常的论点是因为在未来的某个时刻,您可能需要访问该变量才能执行更复杂的操作。但是,开始时这种情况的可能性很小,当你谈论常量时,它变得更小。

我会继续将常量暴露为常数。但是,当没有当前需要getter时,我通常也会继续公开变量。 Python工作人员将此称为You Aren't Gonna Need It原则的应用程序。

答案 3 :(得分:2)

显而易见:

class DeepThought
{
public:
    static int GetTheAnswer() { return 42; }
};

答案 4 :(得分:1)

你也可以使用第一个。考虑一下 - 你要将什么逻辑放入GetTheAnswer()?你不能改变它的签名或它是静态的事实而不破坏它的界面考虑因素。这意味着除非你要开始制作非恒定的全局变量,这将是极其糟糕的,你在GetTheAnswer()中没有任何东西可以放在TheAnswer的constexpr中。分配给。

此外,使用GetTheAnswer()可以做些什么是有限制的,例如,在第一个你可以使用常量的地址和GetTheAnswer(),你不能,即使它是非常合理,你应该能够。

答案 5 :(得分:0)

这些常量基本上都是隐藏的单例模式。只有一个常量实例可用。这将是此类代码的正常演变:

class DeepThought {
public:
   static const int i=10;
   void f() { std::cout << i; }
};

然后你想要在运行时改变变量,它会变成这样:

   class Singleton {
      static Singleton &get() { static Singleton s; return s; }
      int get_i() const { return i; }
   };
   class DeepThought {
   public:
     void f() { std::cout << Singleton::get().get_i(); }
   };

然后在某些时候你会想要不止一个常数的实例,它会变成这样:

  struct Data
  {
     int i;
  };
  class DeepThought {
  public:
    DeepThought(Data &d) : d(d) { }
    void f() { std::cout << d.i; }
  private:
    Data &d;
  };
  int main() { Data d; DeepThought dt(d); dt.f(); }

在代码发展过程中,它会发生很大的变化,如果你有大量的代码,那么进行更改可能需要付出很大的努力。