程序#1
// file.h
class File
{
public:
static const int var = 9;
};
-
// main.cpp
#include <iostream>
#include "file.h"
using namespace std;
int main() {
File f;
cout << f.var;
return 0;
}
程序#2
// file.h
int GlobalVar ;
class File
{
public:
static const int var = 9;
};
-
// main.cpp
extern int GlobalVar;
#include <iostream>
#include "file.h"
using namespace std;
int main() {
cout << GlobalVar;
return 0 ;
}
程序#1运行正常,但程序#2给出链接器错误:
error LNK2005: "int GlobalVar" (?x@@3HA) already defined in file.obj
我知道头文件永远不会被编译。那么在上面的例子中,编译器如何知道变量var的定义,但却无法找到GlobalVar
的定义?
这两个程序有什么区别?
答案 0 :(得分:7)
使用时
#include "some_header.h"
或
#include <some_header.h>
这些include
指令直接*替换为内容为some_header.h
的预处理器。
因此,当您编译cpp
文件时,它实际上包含some_header.h
的内容。这就是编译代码的方式。
* - 如果您有包含警卫,我的内容将被跳过,如果它已被其他标题包含
编辑:关于您的修改 - 关于extern
:这不是正确的方法。
extern int GlobalVar ;
应放在标题和
中int Globalvar ;
应位于 cpp 文件中。您应该阅读更多关于extern
的内容,以了解它是如何工作的以及它的作用(提示:假设您希望只有一个变量,在一个地方定义并且可以在多个cpp中访问文件 - 你会怎么做?关于这种情况,SO中也有很多问题。)
答案 1 :(得分:0)
静态const数据成员有一定的余量,类似于内联函数的允许(在类声明中定义的头文件中的函数或标记为内联的函数)。对于原始类型的静态const数据成员(例如,整数),允许在头文件中定义它们,即使这在技术上会导致一个定义规则(ODR)违规,因为对于这样的原始类型并且假设所有链接器看到的那些数据成员的实例来自相同的头文件,可以安全地假设它们都是相同的。并且因为它们是常量,所以有许多副本(或完全优化它们)没有问题,但如果是非const,那么必须保证单个实例被操纵。并且因为它们是原始类型(具有普通的构造函数),所以静态数据成员的多重构造(在多个翻译单元中)没有副作用的问题,但如果是非原始的,则必须保证在静态初始化期间,构造只发生一次。因此,显然,这个例外规则不适用于非const和/或非原始(类类型)的静态数据成员,在这种情况下,它们必须仅在一个转换单元中定义(一个已编译的cpp)文件)。