我的问题:为了确保它的地址是可用的,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;
}
我的问题:为了确保它的地址是可用的,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;
}
其他的答案已经给出了如何解决它 - 我会去多进为什么。
当你这样做:
#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
必须在一个中定义,并且只有一个翻译单元。要选择它应该驻留的翻译单元,您需要在那里定义它。
你也有你的类上面的代码无效的问题,但 - 只有静态常量组成成员可能与你所使用的语法(把K = 7.7类体)来初始化 - float
不一个完整的类型。
其中一个是类内是可变k
的声明。你需要定义它恰好在一个翻译单位为了正确地链接你的程序。因此,该声明是必需的。
s /编译单元/翻译单元/和我会+1;) – 2010-09-09 06:42:32
“定义”类实际上只提供A::k
的“声明”。是的,我知道它很混乱,但我的想法是允许类定义在.h
(包含多个.cpp
来源)中,而不会产生歧义:这些来源中的一个且只有一个必须提供实际的定义以匹配A::k
的声明(后者是类别A
的定义的一部分)。
类内部是声明。所以如果我不定义* C++仍然允许我访问它?显然cout << A :: k工作正常。 – Fanatic23 2010-09-09 05:03:16
@Arpan:是的,但该代码根据标准无效。因此你的编译器可以做任何喜欢的事情。 – 2010-09-09 05:15:33
@Billy ONeal:3美元。2/2-“如果其名称出现在可能评估的表达式中,则使用对象或非重载函数。”当A :: k用作'<<'操作符的操作数时,它将被评估。一个对象只有在存在和被定义的情况下才能被评估。所以,如果A :: K没有定义,它真的是一个未定义的行为,或者它是一个需要诊断的错误(在这种情况下在链接阶段)。 – Chubsdad 2010-09-09 06:33:22
一个静态变量可以被认为是由该类的所有对象共享的数据,因此应该只创建该变量的一个副本。有了这个说法,谁应该为这个成员分配内存的责任呢?显然,它不能成为对象的责任,因为可能有多个对象会引发另一个挑战,即哪个对象应该为这个成员分配内存。
所以通常compliler预计淘汰类,这个成员的明确定义,因此该行:
const float A::k;
这确保了静态成员变量是在类的所有对象的访问。此变量的内存分配在全局可访问的内存中。
这听起来像你想知道为什么变量需要定义,即使你没有访问它。
要打印它的地址,它需要一个地址。有一个地址,它必须存在。为了存在,它需要有一个定义,并且链接器需要为它在全局变量空间中分配一个位置。所以,真的没有一个中间立场。
“引擎盖下”,该定义告诉链接器全局的初始化器是什么。 (在这种情况下,初始化程序位于class
块中,但这不是标准的,官方的方式是编写const float A::k = 7.7;
)。不知道它不能生成可执行文件。
而且,除非编译器执行不可能详细的分析,它不能真正告诉operator <<
不以某种方式说指针传递给其他一些功能或OS服务,将访问k
值。
如果你可以这样定义static const float k = 7.7;
如你所愿,你将在多重定义结束(因为静态成员将只有一次定义),无论你是包括它。
为了避免定义在cpp
文件中单独存在。
从C++标准文档秒9.4.1,
静态数据成员是不是类的子对象的一部分。有只有一个副本静态数据成员共享 所有对象的类。
另外9.4.2指出,
在其类定义静态数据成员的声明是不是定义,并且可以是一个不完整的类型 比CV-合格空隙其他的。对于静态数据成员的定义应在的命名空间范围中出现,其中包含 成员的类定义。
希望它可以帮助..
可能的重复:http://stackoverflow.com/questions/3575580/rationale-behind-static-const-member-initialization-syntax – sje397 2010-09-09 04:52:45
这不是重复的。我想了解为什么cout << A :: k有效,但不是cout << &A::k; – Fanatic23 2010-09-09 05:04:58
该代码不应该编译。只有静态const **集成**成员可以在类中以这种方式进行初始化。 – 2010-09-09 05:14:46