【问题标题】:c++ private static member variables compared to free nonmemberc ++私有静态成员变量与免费非成员相比
【发布时间】:2015-04-16 20:02:02
【问题描述】:


我对 C++ 比较陌生,并且对 private 静态成员或“免费非成员”有疑问。

我可以这样写代码:

// 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 版?

亲切的问候
尼西

【问题讨论】:

  • 很难选择。大多数时候你不应该使用这些。如今,静态变量和全局变量都被认为是一种代码异味。
  • 这主要是语义上的东西:iValue 是否与MyClass 密切相关?那么它应该在课堂上。如果它只是一些与MyClass 关系不大的 CPP 中需要的幻数,那么请将其分开。请记住,C++ 从 C 开始,然后在它之上构建——你可能有 namespace 等,但在任何地方都没有使用类......

标签: c++ private member


【解决方案1】:

这个领域的设计决策需要平衡一些事情,这很容易理解,这样你就可以在每次需要这样的选择时权衡利弊:

  • 匿名命名空间或静态非成员允许在翻译单元所有以后的代码完全访问。

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

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

      • 这通常被认为具有比私有成员变量更少的封装,因为多个类的代码和朋友可以访问/更改数据(但类成员的定义可能分布在许多翻译单元,并且私有数据更容易受到某些类型的“黑客”访问,例如客户端提供的模板专业化 - 没有什么是干净利落的)。

        • 如果您希望翻译单元中的更多代码能够访问,则需要较少的封装:您正在寻找一种“适合”实际需求的方式。
      • 这减少了(重新)编译依赖性(在拉科西亚语中也称为“物理依赖性”),这意味着您可以在不编辑标题的情况下更改数据/功能,并且仅重新编译翻译单元可以让新数据/behaviour 被许多客户端对象/可执行文件链接以合并;这与对头文件的编辑形成对比,后者往往需要重新编译并重新链接所有客户端代码以进行合并。在企业级开发中,这对于低级库的更改可能是一个大问题。

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

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

【讨论】:

    【解决方案2】:

    MyClass(类,而不是实例)有 iValue 吗?

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

    不 => 做其他事情。

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

    做正确的事的人的另一点:关注点分离,你的班级应该做一件事并且只做一件事。如果 iValue 在课堂上无所事事,但你有点希望它出现在某个课堂上:吉米,不要这样做。

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

      • 为什么文件本地 static 常量“设计不当”?
      猜你喜欢
      • 1970-01-01
      • 2016-05-20
      • 2020-03-22
      • 1970-01-01
      • 1970-01-01
      • 2020-01-27
      • 2012-02-18
      • 1970-01-01
      • 2012-04-13
      相关资源
      最近更新 更多