C++中变量的声明和定义之间有什么区别
What is the difference between declaration and definition of a variable in C++?
我的问题源于Scott Meyers对Effective C++的研究。在这本书的第二项中,写了以下内容:
若要将常量的作用域限制为类,必须将其设为成员;若要确保常量最多有一个副本,必须将它设为静态成员。
这是正确的。然后立即给出以下示例:
class GamePlayer {
private:
static const int NumTurns = 5;
int scores[NumTurns];
....
};
然后写下与上述示例相关的内容:
您在上面看到的是声明,而不是NumTurns的定义。
我的第一个问题是:这句话的含义是什么
紧接着提到以下内容:
通常C++要求您为所使用的任何东西提供一个定义,但静态和整型的类特定常量(例如-integers、chars、bools)除外。只要你不记录他们的地址,你就可以在不提供定义的情况下声明和使用他们。如果你确实获取了类常量的地址,或者如果你的编译器错误地坚持定义,即使你没有获取地址,你也可以提供一个单独的定义,如下所示:
const int GamePlayer::Numturns; //definition of NumTurns
为什么现在它是一个定义而不是声明
我理解函数上下文中的差异,但不理解正则变量上下文中的区别。此外,有人能详细说明作者所说的是什么意思吗
。。。如果你确实取了一个类常量的地址,或者如果你的。。上面引用的段落的一部分?
p.S:我在C++方面还是个新手。
与函数一样,变量可以有"纯声明性"声明和实际定义。您会感到困惑,因为您以前可能没有遇到过很多纯变量声明。
int i; // Definition
extern int i, j; // (Re)declares i, and declares j
extern int j = 0; // Defines j (confusing, eh?)
正如您习惯于使用函数一样,定义是声明,但并非所有声明都是定义。§3.1/2读取
声明是定义,除非[…]声明静态数据类定义中的成员(9.2,9.4),
因此,类中的静态数据成员声明永远不会定义它们声明的变量。然而,有时,变量定义并不一定存在。这就是的情况,当您可以直接使用它的值,而不必在运行时存在变量
从技术角度讲,只要静态数据成员(或任何实体)不是"odr使用的",就不必定义它所有实体的Odr使用定义见§3.2/3:
一个变量
x
,其名称显示为可能求值的表达式ex
由ex
使用odr,除非将左值应用于右值转换(4.1)到x
产生不调用的常量表达式(5.20)任何非平凡函数,如果x
是对象,则ex
是表达式e
的一组潜在结果,其中左值到右值的转换(4.1)应用于e
,或者e
是废弃值表达式(第5条)。
这看起来很复杂,在标准的早期版本中更简单。然而,它粗略地说,当某个表达式"立即"访问变量值时,该变量不是该表达式所使用的odr,并且该访问生成一个常量表达式。Meyers的"获取其地址"示例只是odr使用的众多示例之一。
对于某些类别A
及其静态数据成员i
,
class A {
static const int i = 57; // Declaration, not definition
};
const int A::i; // Definition in namespace scope. Not required per se.
这里指出:
在类接口中初始化的静态
const
积分数据成员不是可寻址变量。它们只是相关价值的象征性名称。由于它们不是变量,因此无法确定它们的地址。请注意,这不是一个编译问题,而是一个链接问题。在类接口中初始化的静态const
变量不作为可寻址实体存在。
此处所指的"可寻址实体"是静态const
数据类型的"实例"。没有实例,没有地址,也就是说,它只是一个声明
请注意,在源文件中明确定义的静态变量可以正确链接。
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
}
。。。如果你确实取了一个类常量的地址,或者如果你的。。上面引用的段落的一部分?
这意味着如果使用这样的成员,则仍然需要命名空间范围内的定义,但它不应该有初始值设定项。
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
为什么现在它是一个定义而不是声明
因为此语句会导致编译器为静态变量生成一个地址。
此外,有人能扩展作者所说的"如果你真的接受类常量的地址":
当您使指针指向变量时,您获取其地址。
一个简短的答案是:一个声明说"这个东西存在于某个地方",而一个定义导致空间被分配。在您的案例中,您已经将其声明为static和const。编译器可能足够聪明,可以注意到,如果您只将其用作值,它可以简单地将该用法替换为文字5。它实际上不需要为某个地方的变量腾出空间并用5填充,它可以在编译时直接使用5。然而,如果你取了它的地址,编译器就不能再做出这样的假设,现在需要把5放在可寻址的地方。编译器需要它存在于一个翻译单元中(大致为:一个cpp文件。另请参阅一个定义规则。),所以现在必须在某个地方显式声明它。
- Mix_Init和Mix_OpenAudio SDL之间的区别是什么
- 我是C++编程的新手,这些代码之间有什么区别,我应该使用哪一个
- 在两台机器之间进行时间戳的最佳c++chrono函数是什么
- 这 4 个 lambda 表达式之间有什么区别?
- 空指针常量 (nullptr)、空指针值和空成员指针值之间有什么区别?
- 不同的类或结构初始化方法之间的性能差异是什么?
- "constinit"和"constexpr"之间的真正区别是什么?
- 在什么条件下使用 std::memcpy 在对象之间复制是安全的?
- 移动语义和深层/浅层复制之间有什么关系?
- 这两种C++语法之间有什么区别?
- #include < conio.h> 和 getch() 方法之间的关系是什么?
- ((int) a) 和 (int(a)) 之间的区别是什么?
- ( var > x) 和 ( x < var)之间有什么区别吗?
- 在 C 和 C++ 中作为函数参数,int **a 和 int a[][] 之间有什么确切的区别
- 返回引用实例和非引用实例(return mystr & vs mystr)之间的区别是什么?
- 超市管理系统的类别之间应该是什么关系?
- 指针和程序性能之间有什么关系吗?
- 这些初始化之间有什么区别?
- 空字符和"\0"之间有什么区别?
- 无符号长整型和无符号 int 之间有什么区别,这 2 种类型应该如何在 c# 中封送?