2010-09-09 60 views
2

我的问题:为了确保它的地址是可用的,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

可能的重复:http://stackoverflow.com/questions/3575580/rationale-behind-static-const-member-initialization-syntax – sje397 2010-09-09 04:52:45

+0

这不是重复的。我想了解为什么cout << A :: k有效,但不是cout << &A::k; – Fanatic23 2010-09-09 05:04:58

+1

该代码不应该编译。只有静态const **集成**成员可以在类中以这种方式进行初始化。 – 2010-09-09 05:14:46

回答

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必须在一个中定义,并且只有一个翻译单元。要选择它应该驻留的翻译单元,您需要在那里定义它。

你也有你的类上面的代码无效的问题,但 - 只有静态常量组成成员可能与你所使用的语法(把K = 7.7类体)来初始化 - float不一个完整的类型。

1

其中一个是类内是可变k声明。你需要定义它恰好在一个翻译单位为了正确地链接你的程序。因此,该声明是必需的。

+0

s /编译单元/翻译单元/和我会+1;) – 2010-09-09 06:42:32

2

“定义”类实际上只提供A::k的“声明”。是的,我知道它很混乱,但我的想法是允许类定义在.h(包含多个.cpp来源)中,而不会产生歧义:这些来源中的一个且只有一个必须提供实际的定义以匹配A::k声明(后者是类别A定义的一部分)。

+0

类内部是声明。所以如果我不定义* C++仍然允许我访问它?显然cou​​t << A :: k工作正常。 – Fanatic23 2010-09-09 05:03:16

+0

@Arpan:是的,但该代码根据标准无效。因此你的编译器可以做任何喜欢的事情。 – 2010-09-09 05:15:33

+0

@Billy ONeal:3美元。2/2-“如果其名称出现在可能评估的表达式中,则使用对象或非重载函数。”当A :: k用作'<<'操作符的操作数时,它将被评估。一个对象只有在存在和被定义的情况下才能被评估。所以,如果A :: K没有定义,它真的是一个未定义的行为,或者它是一个需要诊断的错误(在这种情况下在链接阶段)。 – Chubsdad 2010-09-09 06:33:22

0

一个静态变量可以被认为是由该类的所有对象共享的数据,因此应该只创建该变量的一个副本。有了这个说法,谁应该为这个成员分配内存的责任呢?显然,它不能成为对象的责任,因为可能有多个对象会引发另一个挑战,即哪个对象应该为这个成员分配内存。

所以通常compliler预计淘汰类,这个成员的明确定义,因此该行:

const float A::k;

这确保了静态成员变量是在类的所有对象的访问。此变量的内存分配在全局可访问的内存中。

1

这听起来像你想知道为什么变量需要定义,即使你没有访问它。

要打印它的地址,它需要一个地址。有一个地址,它必须存在。为了存在,它需要有一个定义,并且链接器需要为它在全局变量空间中分配一个位置。所以,真的没有一个中间立场。

“引擎盖下”,该定义告诉链接器全局的初始化器是什么。 (在这种情况下,初始化程序位于class块中,但这不是标准的,官方的方式是编写const float A::k = 7.7;)。不知道它不能生成可执行文件。

而且,除非编译器执行不可能详细的分析,它不能真正告诉operator <<不以某种方式说指针传递给其他一些功能或OS服务,访问k值。

1

如果你可以这样定义static const float k = 7.7;如你所愿,你将在多重定义结束(因为静态成员将只有一次定义),无论你是包括它。

为了避免定义在cpp文件中单独存在。

从C++标准文档秒9.4.1,

静态数据成员是不是类的子对象的一部分。有只有一个副本静态数据成员共享 所有对象的类。

另外9.4.2指出,

在其类定义静态数据成员的声明是不是定义,并且可以是一个不完整的类型 比CV-合格空隙其他的。对于静态数据成员的定义应在命名空间范围中出现,其中包含 成员的类定义。

希望它可以帮助..