【问题标题】:Declaring static data members of normal class and class template声明普通类和类模板的静态数据成员
【发布时间】:2013-03-15 23:51:14
【问题描述】:

我读到在源文件中定义静态数据成员的原因是因为如果它们在头文件中并且多个源文件包含头文件 - 定义将多次输出。我可以理解为什么这对于静态 const 数据成员来说是个问题,但是为什么对于静态数据成员来说这是个问题呢?

我不太确定我是否完全理解如果定义写在头文件中会出现问题...

【问题讨论】:

    标签: c++ oop static constants


    【解决方案1】:

    变量的多重定义问题是由于语言定义中的两个主要缺陷。

    如下所示,您可以轻松解决它。没有直接支持的技术原因。这与委员会成员选择将其作为优先事项的功能需求不够高有关。

    首先,为什么多个定义通常是个问题。由于 C++ 缺乏对单独编译模块的支持(缺陷 #1),程序员必须通过使用文本预处理等来模拟该功能。然后很容易不经意地引入两个或多个同名定义,这很可能会出错。

    对于函数,这是通过 inline 关键字和属性解决的。独立函数只能显式为inline,而成员函数可以通过在类定义中定义隐式为inline。无论哪种方式,如果一个函数是inline,那么它可以在多个翻译单元中定义,并且必须在使用它的每个翻译单元中定义,并且这些定义必须是等价的。

    主要是该解决方案允许在头文件中定义类。

    不需要这样的语言特性来支持数据,头文件中定义的变量,所以它不存在:你不能有inline 变量。这是语言缺陷#2。

    但是,您可以通过对类模板的static 数据成员的特殊豁免来获得inline 变量的效果。豁免的原因是类模板通常必须在头文件中完全定义(除非模板仅在翻译单元内部使用),因此类模板能够具有static 数据成员,它是在一般规则的豁免或某些特殊支持下是​​必要的。委员会选择了豁免规则路线。

    template< class Dummy >
    struct math_
    {
        static double const pi;
    };
    
    template< class Dummy >
    double const math_<Dummy>::pi = 3.14;
    
    typedef math_<void> math;
    

    以上被称为模板化的 const 技巧。据我所知,我曾经是在 [comp.lang.c++] Usenet 组中介绍它的人,所以我不能把功劳归功于其他人。我也在 SO 上发布了几次。

    无论如何,这意味着每个 C++ 编译器和链接器都在内部支持并且必须支持 inline 数据所需的机制,但该语言没有该功能。

    但是,另一方面,C++11 有constexpr,您可以在其中编写上述内容

    struct math
    {
        static double constexpr pi = 3.14;
    };
    

    嗯,有一个区别,你不能取 C++11 math::pi 的地址,但这是一个很小的限制。

    【讨论】:

      【解决方案2】:

      我认为您混淆了两件事:static 数据成员和全局变量标记为static

      后者有内部链接,这意味着如果你把它们的定义放在一个头文件中,多个翻译单元#include,每个翻译单元都会收到一个私有副本 这些变量。

      标记为const 的全局变量默认具有内部链接,因此您无需为它们显式指定static。因此,链接器不会抱怨全局const 变量或标记为static 的全局非const 变量的多个定义,而在其他情况下它会抱怨(因为这些变量将具有外部链接)。

      关于 static 数据成员,这是 C++11 标准的第 9.4.2/5 段所说的:

      static 命名空间范围内类的数据成员具有外部链接 (3.5)。本地类不应有 static 数据成员。

      这意味着如果你将它们的定义放在多个翻译单元的头文件#included 中,你最终会在对应的目标文件中得到同一个符号的多个定义(完全像非const 全局变量),无论他们的const-qualification 是什么。在这种情况下,您的程序将违反 One Definition Rule

      另外,this Q&A on StackOverflow 可以让您更清楚地了解该主题。

      【讨论】:

      • 好的,原因与这个内部与外部链接问题有关吗?普通数据成员具有内部链接,而静态(静态/常量静态)具有外部链接?
      • @user997112:非静态数据成员具有它们所属的对象的链接。其实,我觉得谈非静态数据成员的“联结”甚至都不合适。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-20
      • 1970-01-01
      相关资源
      最近更新 更多