我的问题:为了确保它的地址可用,k在课外定义究竟是什么?
#include <iostream>
using namespace std;
class A {
public:
static const float k = 7.7;
};
//const float A::k; --> without this line compiler error
int main()
{
cout << &A::k;
}
答案 0 :(得分:2)
类“定义”实际上只提供A::k
的“声明”。是的,我知道这很令人困惑,但我们的想法是允许类定义在.h
(包含在多个.cpp
来源中),而不会产生歧义:其中一个,只有一个{{ 1}}来源,必须提供实际的定义以匹配.cpp
的声明(后者是类A::k
的的一部分>定义)。
答案 1 :(得分:1)
类中的一个是变量k
的声明。您需要在一个翻译单元中定义它才能正确链接您的程序。因此该声明是必需的。
答案 2 :(得分:1)
听起来你想知道为什么即使你没有访问它也需要定义变量。
要打印其地址,需要有一个地址。要有地址,它必须存在。要存在,它需要有一个定义,链接器需要在全局变量空间中为它分配一个位置。所以,真的没有中间立场。
“引擎盖下”,该定义告诉链接器全局的初始化器是什么。 (在这种情况下,初始化程序位于class
块中。但这是非标准的。官方方法是编写const float A::k = 7.7;
)在不知道的情况下,它不能生成可执行文件。
此外,除非编译器执行不可能详细的分析,否则它无法真正告诉operator <<
不会以某种方式将该指针传递给将访问的其他函数或OS服务价值k
。
答案 3 :(得分:1)
如果你可以按照自己的意愿定义static const float k = 7.7;
,那么你最终会有多个定义(因为静态成员只会定义一次),无论在哪里你包括它。
避免将定义单独驻留在cpp
文件中。
来自C ++标准文档第9.4.1节,
静态数据成员不属于类的子对象。 只有一个副本的静态数据成员共享 通过班级的所有对象。
同样9.4.2声明,
静态数据成员在其类定义中的声明不是定义,可能是不完整的类型 除了cv-qualified void之外。静态数据成员的定义应在命名空间范围中出现,其中包含 成员的班级定义。
希望有所帮助......
答案 4 :(得分:1)
其他答案已经给出了如何解决它 - 我会更多地了解原因。
执行此操作时:
#include <iostream>
using namespace std;
class A {
public:
static const float k = 7.7;
};
int main()
{
cout << A::k;
}
编译器可能实际上产生了这个:
#include <iostream>
using namespace std;
class A {
public:
static const float k = 7.7;
};
int main()
{
cout << 7.7;
}
这意味着此翻译单元与A::f
之间不会存在链接时间依赖关系 - 编译后的代码根本不会引用A::f
!
但是,当您使用&A::f
时,会强制编译器为A::f
生成地址。因此,翻译单元确实依赖A::f
。由于您尚未定义它,因此链接器错误,因为链接器无法找到它的地址。对于要存在的地址,必须在一个且仅一个翻译单元中定义A::f
。要选择它应该驻留的翻译单元,您需要在那里定义它。
您的上述类也存在无效的代码问题 - 只有 static const integral 成员可以使用您使用的语法进行初始化(在类体中放置k = 7.7) - - float
不是一个整体类型。
答案 5 :(得分:0)
静态变量可以视为类的所有对象共享的数据,因此只应创建此变量的一个副本。有了这个说,谁应该为这个成员分配内存的责任?显然它不是对象的责任,因为可能有多个对象会引起另一个挑战,即哪个对象应该为该成员分配内存。
因此,通常compliler期望该成员的明确定义,因此行:
const float A::k;
这确保了类的所有对象都可以访问静态成员变量。此变量的内存分配在全局可访问的内存中。