头文件中的内容在编译时会填充到include这个头文件的cpp文件中,所以头文件中有什么东西,相当于cpp文件中也有什么东西,如果有多个include这个头文件的cpp文件,
那么它们相当于都获得了这个头文件中的内容的一个副本,发生重定义错误。所以很多东西的定义不能放在头文件,只能放声明,否则会出现多个副本。
static的使用:
在c++引入命名空间之前,程序需要将名字声明成static的以使其只对整个文件有效,而对外部文件不可见。这个做法继承自C语言,但引入命名空间后,这个做法已经被取消了,现在的做法是在未命名的命名空间内存放对象。(c++ primer P701)
所以:
1. 如果希望对象只能在文件内访问,就把它放到文件内的未命名空间。
2. 如果是需要多个文件共同访问的全局对象,则在其中一个cpp文件中(注意全局对象的定义不能放在头文件)使用单例模式:
extern int targetObj(){ static int obj = 1; return obj; }
使用单例模式的原因:
c++对“定义于不同的编译单元内的non-local static对象”的初始化相对次序并无明确定义。比如A,B两个对象分别定义于不同的cpp文件,A对象的初始化依赖B对象,所以B对象的初始化必须先于A对象。
c++保证,函数内的local static对象会在“该函数被调用期间”“首次遇到这个local static对象”时被初始化,所以把B对象放到类似上面的targetObj函数内,A在使用B时调用单例模式函数,就能保证B已经被初始化。(effective c++ P31)
3. 对于会被多个不同的cpp文件调用的全局对象(例如上面这个单例模式函数),它的定义可以放在某个cpp文件中,前面加上extern,然后在头文件的函数声明中也加上extern,
这样其他cpp文件要调用这个函数只需要include这个头文件即可。(c++ primer P54)
总结:
头文件内只放各种对象的声明,而定义放在cpp文件中(内联函数,函数模板,模板类,模板显式实例化除外),对于多个cpp共用的全局变量,将其定义放在其中一个cpp文件(需要保证初始化顺序时使用单例模式),
然后在定义和声明前面都加上extern,其他cpp文件使用的使用直接在文件内进行extern声明即可。对于只在文件内使用的对象,将其定义放到未命名空间内。
对于宏定义和typedef,如果只在一个cpp文件中使用,则放在这个cpp文件中;若果多个源文件中需要使用这个宏,则放在头文件中定义。
// radio.h #ifndef __RADIO_H__ #define __RADIO_H__ // 应包含内容 class Radio // 正确:类定义 { static int s_count; // 正确:静态数据成员声明 static const double S_PI; // 正确:静态常量数据成员声明 int d_size; // 正确:数据成员定义 // ... public: int size() const; // 正确:成员函数声明 // ... }; inline int Radio::size() const // 正确:内联函数定义 { return d_size; } // 不应包含内容 int Radio::s_count; // 错误:静态数据成员定义,应放在 .cpp 文件中 double Radio::S_PI = 3.1415926; // 错误:静态常量数据成员定义,应放在 .cpp 文件中 int Radio::size() const { /*...*/ } // 错误:成员函数定义,应放在 .cpp 文件中 int z; // 错误:外部数据定义 extern int LENGTH = 10; // 错误:外部数据定义 const int WIDTH = 5; // 避免:常量数据定义 static int y; // 避免:静态数据定义 static void func() { /*...*/ } // 避免:静态函数定义 #endif // __RADIO_H__
在 C++ 头文件的作用域内放置带有内部链接的定义,如静态函数或数据,是合法的,但是这种做法并不理想。这样不仅污染了全局名称空间,而且包含该头文件的每一个编译单元中消耗数据空间。
标签:文件,头文件,定义,int,东西,static,cpp,应该 From: https://www.cnblogs.com/tan-wm/p/17372299.html