C++中有的東西需要放在可以在.h文件中定義,有的東西則必須放在.cpp文件中定義,有的東西在不同的cpp文件中的名字可以一樣,而有的則不能一樣
那么究竟哪些東西可在頭文件中定義,聲明,哪些東西又必須在.cpp中定義,聲明呢?
*以下所有的討論都是在全局命名空間中(即不定義自己的namespace)下進行的
函數
1、在.h中只能聲明函數,在.cpp中可以聲明與定義函數
如果在.h中聲明並定義一個函數,則該函數只能被#include一次,否則則會出現重定義錯誤
比如
1.h
#pragma once void show() { }
a.cpp
#include "1.h"
b.cpp
#include "1.h"
error LNK2005: "void __cdecl show(void)" (?show@@YAXXZ) 已經在 a.obj 中定義
所以要避免在頭文件中定義函數
2、在不同.cpp中定義的函數原型(函數返回值,函數名稱,函數參數)不能完全一樣,
比如如果有在兩個.cpp文件中均存在
void show(){};
會出現重定義錯誤
內聯函數
為了確保所有調用該inline函數的文件中的定義一樣,所以需要是在.h文件中定義
注意這里的inline對於編譯器來說只是建議性的,關於該內聯函數被拒絕會在下一篇文章中介紹
typedef
在不同的cpp中可以一樣
變量
1、在.h中只能聲明,在.cpp中可以聲明與定義一個變量
如果在.h中的定義一個變量,則該變量被include兩次以上時則會出現重定義錯誤
2、在不同.cpp中定義的變量的名字與類型不同一樣
常量
1、如果const常量是用常量表達式進行初始化的,則可以在.h中聲明與定義
2、如果const變量是用非常量表達式進行初始化的,那么該變量應該在cpp文件中定義,而在.h文件中進行聲明。
3、不同cpp中以定義名字與類型一樣的變量
static變量
1、在不同的cpp中可以定義名字與類型一樣的變量
2、如果在.h中定義一個static成員,則所有include該文件的文件均擁有一份獨立的該static成員,一個文件對其的修改不會影響到另一個文件
所以static變量一般是放在.cpp出現並定義.
例如
1.h
#pragma once static int a = 5;
a.cpp
#include "1.h" #include <iostream> using namespace std; void showstatic() { cout << "In a.cpp:" << a << endl; a = 1; cout << "In a.cpp:" << a << endl; }
b.cpp
#include "1.h" #include <iostream> using namespace std; void showstatic(); int main() { showstatic(); cout << "In b.cpp:" << a << endl; system("pause"); }
static函數
在不同的cpp中可以定義函數原型一樣的函數
類
不同的cpp中類的名字可以一樣
類成員與函數
在.h中定義,所有成員必須在類中聲明,在cpp中實現
非靜態的常量整形數據成員不能就地初始化(*C++11中,標准允許使用等號=或者花括號{}進行就地的非靜態成員變量初始化)
在類內部定義的成員函數將自動作為inline處理
在.h外部定義的函數需要加上inline說明
否則在被include多次時會出現重定義錯誤
1.h
#pragma once #include <iostream> class A { public: void show(); }; void A::show()//無inline { std::cout << "hello" << std::endl; }
a.cpp
#include "1.h" #include <iostream> using namespace std;
b.cpp
#include "1.h" #include <iostream> using namespace std;
error LNK2005: "public: void __thiscall A::show(void)" (?show@A@@QAEXXZ) 已經在 a.obj 中定義
類的const成員
在類中聲明變量為const類型的成員不可以就地初始化
const常量的初始化必須在構造函數初始化列表中初始化,而不可以在構造函數函數體內初始化(*C++11中,標准允許使用等號=或者花括號{}進行就地的非靜態成員變量初始化)
#pragma once class A { public: const int i=50; };
error C2864: “A::i”: 只有靜態常量整型數據成員才可以在類中初始化 d:\我的資料庫\documents\visual studio 2010\projects\fasd\fasd\1.h 5 1 fasd
類的靜態的數據成員
不可以就地初始化,需要到.cpp中進行定義
(對於非常量的靜態成員變量,C++11與C++98保持了一致。需要到頭文件以外去定義它)
類的靜態的常量整形數據成員
可以就地初始化
如
class A { private: const static int i = 5; };
模板(不考慮export)
模板函數與模板類的聲明與實現必須放在一個文件中
總結
| 是否可以在.h中定義 | 在不同.cpp中是否可以重名 | 特殊說明 | |
| 函數 | 不可以,會出現重定義錯誤 | 不可以 | |
| 內聯函數 | 可以 | 可以 | 為了確保所有調用該inline函數的文件中的定義一樣,所以需要是在.h文件中定義 |
| typedef | ---------------------- | 可以 | |
| 常量 | 可以 | 可以 | 1、常量表達式進行初始化的,則可以在.h中聲明與定義 2、非常量表達式進行初始化的,那么該變量應該在cpp文件中定義,而在.h文件中進行聲明。 |
| 變量 | 不可以,會出現重定義錯誤 | 不可以(類型與名字) | |
| static變量 | 可以 | 可以 | 在.h中定義一個static成員,則所有include該文件的文件均擁有一份獨立的該static成員,一個文件對其的修改不會影響到另一個文件 所以static變量一般是放在.cpp出現並定義. |
| static函數 | 可以 | 可以 |
| 是否可以在.h中定義 | 是否可以就地初始化 | 特殊說明 | |
| 類 | 可以 | ||
| 類數據成員 | ------------------ | 不可以 | (*C++11中,標准允許使用等號=或者花括號{}進行就地的非靜態成員變量初始化) |
| 類成員函數 | ------------------ | ---------------- | 在.h外部定義的函數需要加上inline說明 否則在被include多次時會出現重定義錯誤 |
| 類const數據 | ------------------ | 不可以 | 1、在類中聲明變量為const類型的成員不可以就地初始化 const常量的初始化必須在構造函數初始化列表中初始化,而不可以在構造函數函數體內初始化 2、同類數據成員中的特殊說明 |
| 類的靜態的數據成員 | ------------------- | 不可以 | 不可以就地初始化,需要到.cpp中進行定義 (對於非常量的靜態成員變量,C++11與C++98保持了一致。需要到頭文件以外去定義它) |
|
類的靜態的常量整形數據成員 |
------------------ | 可以 |
| 特殊說明 | |
| 模板 | 模板函數與模板類的聲明與實現必須放在一個文件中 |
至於為什么會這樣,與C++的編譯和鏈接,和編譯產生的目標文件(.obj),內部鏈接,外部鏈接有關,
我會在接下來的文章中向大家介紹

