C ++中变量的声明和定义有啥区别? [复制]
Posted
技术标签:
【中文标题】C ++中变量的声明和定义有啥区别? [复制]【英文标题】:What is the difference between declaration and definition of a variable in C++? [duplicate]C ++中变量的声明和定义有什么区别? [复制] 【发布时间】:2015-07-09 08:33:02 【问题描述】:我的问题源于对 Scott Meyers 的 Effective C++ 的研究。 在那本书的第二条中,写了以下内容:
要将常量的范围限制为类,您必须将其设为成员,并且为了确保最多有一个常量副本,您必须将其设为静态成员。
写的很对。然后立即给出以下示例:
class GamePlayer
private:
static const int NumTurns = 5;
int scores[NumTurns];
....
;
那么下面就是上面例子的写法:
您在上面看到的是声明,而不是 NumTurns 的定义。
我的第一个问题是:这句话是什么意思?
紧接着提到以下内容:
通常 C++ 要求您为使用的任何内容提供定义,但静态和整数类型(例如 - 整数、字符、布尔值)的类特定常量是一个例外。只要你不取他们的地址,你可以在不提供定义的情况下声明和使用它们。如果您确实获取了类常量的地址,或者即使您不获取地址,编译器也错误地坚持定义,您可以提供一个单独的定义,如下所示:
const int GamePlayer::Numturns; //definition of NumTurns
为什么现在是定义而不是声明?
我理解函数上下文中的差异,但不理解常规变量上下文中的差异。另外,有人可以通过
来扩展作者的意思吗... 如果您确实获取了类常量的地址,或者如果您的 .. 上面引用的段落的一部分?
P.S : 我是 C++ 的新手。
【问题讨论】:
这本书肯定解释了这一点......另外,快速谷歌搜索带来了这篇解释得很好的文章:cprogramming.com/declare_vs_define.html @Amxx 是的,好点。这也是一个格式非常好的问题。 +1。 这与odr rules 相关,如果一个变量没有被 odr 使用,那么它就不需要类外定义。 ***.com/questions/1410563/… 我喜欢将在类中初始化的静态数据成员称为“带有初始化程序的声明”。它们从来都不是定义。 【参考方案1】:声明here:
在类接口中初始化的静态
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
...如果您确实采用了类常量的地址,或者您的 .. 上面引用的段落的一部分?
means 如果这样的成员被 odr-used,则仍然需要命名空间范围内的定义,但它不应该有初始化程序。
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
【讨论】:
那句话不正确。您可以定义一个 const 整数数据成员并获取其地址。 @Columbo;它的static const
。
抱歉,我删除了静电。评论仍然有效。 coliru.stacked-crooked.com/a/1b633f6939183e52
@Columbo;我好奇。你有任何来自标准的报价吗?
@Columbo - 不,你不能。你不应该对这个答案投反对票(我假设你是投反对票的人。)coliru.stacked-crooked.com/a/9c5df94daf8a700e【参考方案2】:
就像函数一样,变量可以有“纯声明性”声明和实际定义。你很困惑,因为你之前可能没有遇到过很多纯变量声明。
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),
因此,类内静态数据成员声明永远不会定义它们声明的变量。但是,有时不必存在变量定义。 当您可以直接使用它的值而不需要变量运行时存在时就是这种情况。
在技术术语中,只要静态数据成员(或任何实体,就此而言)不是“使用过的”,就不必定义它。 §3.2/3 中定义了所有实体的Odr 使用:
变量
x
,其名称显示为潜在评估表达式ex
被ex
odr-used 除非应用左值到右值的转换 (4.1) 到x
产生一个不调用的常量表达式 (5.20) 任何重要的函数,如果x
是一个对象,ex
是一个元素 表达式e
的一组潜在结果,其中 左值到右值转换 (4.1) 应用于e
,或者e
是 丢弃值表达式(第 5 条)。
这看起来很复杂,在标准的早期版本中它更简单。但是,它粗略地说,当某个表达式“立即”访问变量值时,该变量不会被某个表达式使用,并且这种访问会产生一个常量表达式。 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.
【讨论】:
【参考方案3】:为什么现在是定义而不是声明?
因为这个语句会导致编译器为静态变量生成一个地址。
另外,有人可以通过“如果你采取 类常量的地址”:
当你让一个指针指向一个变量时,你会获取它的地址。
【讨论】:
【参考方案4】:简短的回答是:声明说“这东西存在于某处”,而定义导致分配空间。在您的情况下,您已将其声明为静态和常量。编译器可能足够聪明地注意到,如果您只将它用作值,它可以简单地用文字 5 替换该用法。它实际上不需要在某处为变量腾出空间并用 5 填充它,它可以在编译时直接使用 5。但是,如果您获取它的地址,编译器将无法再做出该假设,现在需要将该 5 放入可寻址的某个位置。编译器需要它存在于一个翻译单元中(大致:一个 cpp 文件。另请参见一个定义规则。),所以现在你必须在某处显式声明它。
【讨论】:
以上是关于C ++中变量的声明和定义有啥区别? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
请问C++中啥是函数的定义性声明和函数的引用性声明,有啥区别