C++ c++;私有静态成员变量与自由非成员变量的比较

C++ c++;私有静态成员变量与自由非成员变量的比较,c++,private,member,C++,Private,Member,我对C++是比较新的,并且有一个关于私有< /强>静态成员或“自由NeMeBER”的问题。 我可以这样编写代码: // MyClass.h - Version 1 class MyClass { public: MyClass(); ~MyClass(); private: static int iValue; }; // MyClass.cpp int MyClass::iValue = 123; 另一种方式没有私人成员,在cpp内部有内部链接 // Version


我对C++是比较新的,并且有一个关于<强>私有< /强>静态成员或“自由NeMeBER”的问题。 我可以这样编写代码:

// MyClass.h - Version 1
class MyClass
{
public:
    MyClass();
    ~MyClass();
private:
    static int iValue;
};

// MyClass.cpp
int MyClass::iValue = 123;
另一种方式没有私人成员,在cpp内部有内部链接

// Version 2 - static 
static int iValue = 123;

// or anonymouse namespace
namespace
{
    int iValue2 = 123;
}
我所能看到的唯一区别是,尽管我不能使用它,但在课堂之外的“可见性”
如果我想在派生类之外或派生类中使用iValue,我会在版本1中声明静态成员为public或protected,或者在类之上声明为完全全局的。 对于我来说,关键字const更不清楚

class MyClass
{
private:
    static const int iValue;
// (...)
}
我总是喜欢尽可能多地把东西藏在外面。

简而言之:有什么理由让我更喜欢版本1而不是版本2吗

亲切的问候

Nisi

封装是面向对象编程的主要范例之一,因此,如果静态成员仅由类本身使用(例如,计算类对象的数量),则应使用版本1(私有静态成员)。当然,如果您希望派生类能够使用它,则应该将其设置为受保护的

如果变量未绑定到任何特定的类,并且可以在不同的位置使用,则应使用版本2/3(静态全局变量)。然而,有人可能会说,需要全局变量的代码设计得很糟糕,使用全局变量被认为是一种糟糕的风格

如果您需要特定类别的某个常量值(例如,汽车的车轮数),则可以使用Private static const member。

MyClass(该类别,而非实例)是否具有
iValue

是=>将其设为静态成员

否=>做其他事情

你想知道该怎么做,这表明你现在没有明显的权衡。 这是一个很好的指标,表明您可以而且应该做正确的事情©这就是让其他人尽可能简单地理解您的代码,这反过来意味着:关注代码的语义含义


对于做正确事情的人来说,还有一点:分离关注点,你的班级应该做一件事,并且只做一件事。如果iValue在课堂上无事可做,但你有点希望它在某个课堂的某个地方:吉米,不要这样做。

在这个空间中的设计决策需要平衡一些事情,这些事情很容易理解,因此每次需要这样的选择时,你都可以权衡利弊:

  • 匿名名称空间或静态非成员允许翻译单元中的所有后续代码完全访问

    • 在实现文件(例如“.cc”/.cpp”)中使用,它们允许您在对象的符号表中拥有一些静态数据/函数,而不是
      extern
      ,其他翻译单元的代码无法访问这些数据/函数

      • 较小的符号表有时可以减少程序链接和/或加载时间

      • 这通常被认为比私有成员变量具有更少的封装性,因为不止一个类的代码和朋友可以访问/更改数据(但类成员的定义可能分布在许多翻译单元中,私有数据更容易受到某些类型的“黑客”攻击)访问,如客户提供的模板专业化-没有任何东西是干净的)

        • 如果您希望翻译单元中的更多代码具有访问权限,则需要较少的封装:您正在寻找一个“适合”实际需要的代码
      • 这减少了(重新)编译依赖性(在Lakosian术语中称为“物理依赖性”),这意味着您可以在不编辑标题的情况下更改数据/函数,并且仅重新编译翻译单元就可以链接新的数据/行为,以便由多个客户端对象/可执行文件合并;这与对头文件的编辑形成对比,头文件往往需要重新编译和重新链接所有客户端代码以便合并。在企业级开发中,这可能是低级库更改的一个大问题

    • 它们很少在头文件中使用,因为包含这样一个头文件的每个翻译单元都会获得数据/函数的独立“副本”,并且程序很少希望每个翻译单元存储状态;通常不会清晰地映射到程序数据中逻辑上有意义的分区(例如,每个线程,每个“用户”在运行时),即使程序可以结构化,因此看起来很有用,通常最好使用对象实例管理数据的多个副本,保持它与翻译单元的解耦,为以后的源代码重构/重构保持灵活性

    • 它们不能访问任何类的私有/受保护成员,有人建议它们可能与任何特定类无关,并且可能是可重用的,这取决于这一点的真实程度,在分析数据使用或函数行为/实现时可能有助于或阻碍开发人员的理解


很难选择。大多数时候,你不应该使用这些。如今,静态和全局都被认为是一种代码气味。它主要是一种语义:是不是
iValue
MyClass
密切相关?那么它应该在课堂上。如果它只是一些与
MyClass
关系不大的CPP中所需的幻数,请将其分开。记住C++从C开始,然后在上面建立——你可能有<代码>命名空间< /代码>等,但是不在任何地方使用类…为什么文件“代码<静态< /COD>常数”设计得很差?