c ++私有静态成员变量与自由非成员变量相比

c++ private static member variables compared to free nonmember


我是 C++ 的新手,对 private 静态成员或 "free nonmeber".

有疑问

我可以这样写我的代码:

// 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;
}

我能看到的唯一区别是 class 之外的 "visibility",尽管我无法使用它。
如果我想在派生的 class 之外或派生的 class 中使用 iValue,我会在版本 1 public 中声明静态成员,或者在 class 之上以任何方式保护或完全全局。 关键字const我就更不清楚了。

class MyClass
{
private:
    static const int iValue;
// (...)
}

我总是喜欢尽可能多地隐藏外面的东西。

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

亲切的问候
尼斯

封装是面向对象编程的主要范例之一,因此如果您的静态成员仅由 class 本身使用(例如计算 class 对象的数量),您应该使用版本 1(私有静态成员)。当然,如果你想让派生的 classes 能够使用它,你应该把它变成 protected.

版本 2/3(静态全局变量)应该被使用,如果变量没有绑定到任何特定的 class,并且可以在不同的地方使用。但是,有人可能会争辩说需要全局变量的代码设计得很糟糕,使用全局变量被认为是一种糟糕的风格。

如果您需要一些特定于特定 class 的常量值(例如汽车的车轮数量),可以使用私有静态常量成员。

MyClass(class,不是实例)是否有 iValue

是 => 使其成为静态成员。

否 => 做其他事情。

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

Do the Right Thing 人的另一点:关注点分离,您的 class 应该做一件事并且只做一件事。如果 iValue 在 class 中没有任何关系,但你有点希望它在某个 class 中的某个地方:不要这样做 jimmy.

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

  • 匿名名称spaces或静态non-members允许所有后面的代码在翻译单元 完全访问权限。

    • 用于实现文件(例如“.cc”/“.cpp”),它们让您在 object 的符号 table - 不能被其他翻译单元的代码访问。

      • 较小的符号 tables 有时可以减少程序链接 and/or 加载时间。

      • 这个一般认为是私有成员变量封装少,因为不止一个class的代码朋友可以access/change 数据(但 class 成员的定义可能分布在许多翻译单元中,私有数据更容易受到某些类型的 "hacked" 访问的影响,例如 client-provided 模板特化- 什么都没有 clean-cut).

        • 如果您希望翻译单元中的更多代码能够访问,则需要较少的封装:您正在寻找 "good fit" 实际需要。
      • 这减少了(重新)编译依赖性(在 Lakosian 术语中又称为 "physical dependency"),这意味着您可以在不编辑 header 的情况下更改 data/functions,并且仅翻译单元的重新编译让新的 data/behaviour 可以链接到 however-many 客户端 objects/executables 进行合并;这与对 header 文件的编辑形成对比,这些文件往往需要 重新编译 并重新链接所有客户端代码以进行合并。在 enterprise-scale 开发中,low-level 库的更改可能是一个大问题。

    • 它们很少在header中使用,因为每个包含这样的header的翻译单元都会得到一个独立于 data/functions 的 "copy",程序很少需要按翻译单元存储状态;它通常不会清晰地映射到程序数据中逻辑上有意义的分区(例如,每个线程,每个 "user" 在运行时),即使一个程序可以被构造成看起来很有用,通常最好管理多个副本使用 object 个实例的数据,使其与翻译单元分离,以保持以后源代码的灵活性 refactoring/restructuring.

    • 他们无法访问任何 class 的 private/protected 成员,并且有人建议他们可能与任何特定的 class 无关并且可能可重复使用,在分析数据使用或功能时,这取决于它的真实性,可以帮助或阻碍开发人员的理解 behaviour/implementation.