核心區別
| 概念 | 說明 | 例子 |
| 聲明 | 引入名稱到作用域,不分配存儲(函數除外) | extern int a; void foo(); class A; |
| 定義 | 提供實體完整描述,分配存儲(變量)或生成代碼(函數) | int a = 0; void foo(){} class A{...}; |
一條語句可以同時是聲明和定義(如 int a;),但也有純聲明(extern int a;)和純定義(類外 A::a=0;)。
純聲明場景
- 函數原型:
void func(int, int);
extern 變量聲明(無初始化):extern int a;
- 類前向聲明:
class A;
typedef 聲明
- 類中靜態數據成員聲明:
static int a;
純定義場景
- 類外定義靜態數據成員:
A::a = 0;
- 類外定義非內聯成員函數
鏈接屬性
| 類型 | 鏈接 | 說明 |
| 全局非 static 變量/函數 | 外部鏈接 | 整個程序可見,鏈接時解析符號 |
| static 全局變量/函數 | 內部鏈接 | 僅當前編譯單元可見 |
| const 全局變量 | 內部鏈接 | C++ 默認內部鏈接 |
| 類定義 | 內部鏈接 | 每個編譯單元有自己的定義 |
| 內聯函數 | 內部鏈接 | 編譯器內聯展開,不產生符號 |
| 命名空間內 static/const | 內部鏈接 | |
頭文件最佳實踐
- 只放聲明:函數原型、
extern 變量聲明、類定義、typedef
- 不放定義:非內聯函數定義、非 static 變量定義、靜態成員定義
- 可放內部鏈接定義:
static 函數、const 變量、inline 函數、類定義(但會增加編譯體積)
常見錯誤
- 頭文件中定義全局變量
int a; → 多文件包含導致重複定義錯誤
- 頭文件中定義非內聯函數 → 同理重複定義
- 忘記類外定義靜態成員 → 鏈接錯誤「未定義引用」
- 在類內初始化非靜態成員(C++11 前不允許)