为什么C++静态数据成员需要定义,非静态数据成员不需要?

Why C++ static data members are needed to define but non-static data members do not?

我试图了解静态和非静态数据成员的声明和定义之间的区别。道歉,如果我从根本上想念理解的概念。非常感谢您的解释。

代码试图理解

class A
{
public:
    int ns; // declare non-static data member.
    static int s; // declare static data member. 
    void foo();
    
};
 
int A::s; // define non-static data member.
// int A::ns; //This gives an error if defined.

void A::foo()
{
    ns = 10;
    s = 5; // if s is not defined this gives an error 'undefined reference'
}

当你声明一些东西时,你是在告诉编译器所声明的名称存在以及它是什么类型的名称(类型、变量、函数等)。定义可以与声明一起(就像你的class A) 或者在别处——编译器和链接器稍后必须连接两者。

变量或函数定义的关键点是它告诉编译器和链接器这个variable/function 将存在。如果你有一个变量,它需要在内存中有一个位置。如果您有一个函数,则需要在包含该函数指令的二进制文件中有一个位置。

对于non-static数据成员,声明即定义。也就是说,您是在给他们一个住的地方¹。这个地方在 class 的每个实例中。每次你创建一个新的 A object,它都会附带一个 ns 作为它的一部分。

另一方面,静态数据成员没有关联 object。如果没有定义,您会遇到 A 的 N 个实例都共享相同的 s,但无处放置 s。因此,C++ 让您通过定义为其选择一个翻译单元,通常是 header.

附带的源文件。

你可能会争辩说编译器应该只为它选择一个实例,但由于各种原因这不会起作用,其中一个是你可以在创建实例之前使用静态数据成员,在最后一个实例消失之后,或者根本没有实例。

现在你可能想知道为什么编译器和链接器仍然不能自己解决这个问题,而且......如果你在变量或函数上加上 inline 实际上就会发生这种情况.您最终可以有多个定义,但只会选择一个。


1:给他们住的地方有点跑题了。所有编译器都需要知道它何时创建 class 的 object 是给它多少 space 以及 space 的哪些部分是哪些数据成员。您可以将其视为编译器为您完成定义部分,因为数据成员可能只存在一个地方。

static 变量属于 class 定义。 non-static 变量属于使用 class 定义创建的实例。

int main()
{
    A::s = 5; // this is ok

    A a;
    a.ns = 5 // this is also ok
}

static 成员本质上是全局变量,具有与 class 绑定的特殊名称和访问规则。因此,它们继承了通常全局变量的所有问题。也就是说,在整个 C++ 程序(它是所有翻译单元的联合,也就是 .cpp 文件)中,每个全局变量应该只有一个定义,不能再多了。

你可以把“变量定义”想象成“为变量分配内存的地方”。

然而,classes 通常在头文件 (.h/.hpp/etc) 中定义,该头文件包含在多个翻译单元中。因此,由程序员指定实际定义变量的翻译单元。请注意,自 C++17 以来,我们有 inline 关键字将此负担放在编译器上,请查找“内联变量”。由于历史原因,命名很奇怪。

但是,在您创建 class 的实例(即对象)之前,非 static 成员并不真正存在。对象生命周期和存储持续时间定义了每个成员的状态 created/stored/destroyed。所以没有必要在 class.

之外的任何地方实际定义它们