What is the difference between declaration and definition of a variable in C++?
我的问题源于Scott Meyers研究C++的有效性。在该书的第二项中,写下了以下内容:
To limit the scope of a constant to a class, you must make it a member and, to ensure there's at most one copy of the constant, you must make it a static member.
这是正确的。然后立即给出以下示例:
1 2 3 4 5 6 | class GamePlayer { private: static const int NumTurns = 5; int scores[NumTurns]; .... }; |
然后,针对上述示例编写以下内容:
What you see above is a declaration and not a definition of NumTurns.
我的第一个问题是:这句话的意思是什么?
之后立即提到以下内容:
Usually C++ requires that you provide a definition for anything you use, but class specific constants that are static and of integral type (e.g - integers, chars, bools) are an exception. As long as you don't take their address, you can declare them and use them without providing a definition. If you do take the address of a class constant, or if your compiler incorrectly insists on a definition even if you don't take the address, you provide a separate definition like this :
const int GamePlayer::Numturns; //definition of NumTurns
为什么现在它是一个定义而不是一个声明?
我理解函数上下文中的差异,但不理解正则变量上下文中的差异。另外,有人能进一步阐述作者的意思吗?
... if you do take the address of a class constant, or if your ..
part of the above quoted paragraph ?
P:我是C++的新手。
与函数一样,变量可以有"纯声明性"声明和实际定义。您很困惑,因为您以前可能没有遇到过许多纯变量声明。
1 2 3 | int i; // Definition extern int i, j; // (Re)declares i, and declares j extern int j = 0; // Defines j (confusing, eh?) |
正如您习惯于使用函数一样,定义是声明,但并非所有声明都是定义。3.3.1/2阅读
A declaration is a definition unless […] it declares a static data
member in a class definition (9.2, 9.4),
因此在类中,静态数据成员声明从不定义它们声明的变量。但是,有时变量定义不必存在。在这种情况下,您可以直接使用它的值,而不需要变量的运行时存在。
在技术术语中,只要一个静态数据成员(或任何实体,就此而言)不使用"odr",就不必定义它。所有实体的ODR使用定义见第3.2/3节:
A variable
x whose name appears as a potentially-evaluated expression
ex is odr-used byex unless applying the lvalue-to-rvalue conversion
(4.1) tox yields a constant expression (5.20) that does not invoke
any non-trivial functions and, ifx is an object,ex is an element of
the set of potential results of an expressione , where either the
lvalue-to-rvalue conversion (4.1) is applied toe , ore is a
discarded-value expression (Clause 5).
这看起来很复杂,在早期版本的标准中更简单。但是,它粗略地说,当表达式"立即"访问变量值时,该变量不是某些表达式所使用的ODR,而这种访问会生成一个常量表达式。迈耶斯的"获取其地址"示例只是众多ODR使用示例中的一个。
对于某些类
1 2 3 4 5 | class A { static const int i = 57; // Declaration, not definition }; const int A::i; // Definition in namespace scope. Not required per se. |
在此声明:
Static
const integral data members initialized in the class interface are not addressable variables. They are mere symbolic names for their associated values. Since they are not variables, it is not possible to determine their addresses. Note that this is not a compilation problem, but a linking problem. The staticconst variable that is initialized in the class interface does not exist as an addressable entity.
这里所指的"可寻址实体"是静态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class X { public: static int const s_x = 34; static int const s_y; }; int const X::s_y = 12; int main() { int const *ip = &X::s_x; // compiles, but fails to link ip = &X::s_y; // compiles and links correctly } |
... if you do take the address of a class constant, or if your .. part of the above quoted paragraph ?
这意味着,如果使用了这样的成员odr,则仍需要命名空间范围内的定义,但不应具有初始值设定项。
1 2 3 4 5 | struct X { const static int n = 1; }; const int* p = &X::n; // X::n is odr-used const int X::n; // ... so a definition is necessary |
一个简短的回答是:一个声明说"这个东西存在于某个地方",一个定义导致空间被分配。在您的例子中,您已经声明它是静态的和常量。编译器可能足够聪明,可以注意到如果您只使用它作为一个值,它可以简单地用文字5替换这个用法。它不需要在某个地方为变量留出空间并用5填充,它可以在编译时直接使用5。但是,如果您获取了它的地址,编译器就不能再做出这样的假设,现在需要将5放到某个可寻址的地方。编译器需要它存在于一个翻译单元中(大致是:一个cpp文件)。另请参见一个定义规则),所以现在您必须在某个地方显式声明它。
Why now it is a definition and not a declaration ?
因为这个语句会导致编译器为静态变量生成一个地址。
Also, can someone expand on what the author means by"if you do take
the address of a class constant":
当您将指针指向一个变量时,您会得到它的地址。