是否需要静态变量的类外定义?

时间:2010-09-09 04:45:36

标签: c++

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

6 个答案:

答案 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;

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