class Empty {};
這個空類別到底有哪些隱式成員函數?網路上流傳的「六大預設成員」說法:**預設建構子、拷貝建構子、解構子、拷貝指派運算子、取址運算子、const 取址運算子** —— 這是錯誤的。本文依據 ISO C++ 標準 (C++03/11/14/17/20) 釐清真相。
| 成員函數 | C++98/03 | C++11 起 | 條件 |
|---|---|---|---|
| 預設建構子 | ✓ | ✓ | 無使用者宣告任何建構子 |
| 拷貝建構子 | ✓ | ✓ | 無使用者宣告拷貝建構子 |
| 拷貝指派運算子 | ✓ | ✓ | 無使用者宣告拷貝指派 |
| 解構子 | ✓ | ✓ | 無使用者宣告解構子 |
| 移動建構子 | ✗ | ✓* | 無使用者宣告拷貝/移動/解構子 |
| 移動指派運算子 | ✗ | ✓* | 同上 |
* 符合條件時隱式宣告為 defaulted,不滿足則隱式宣告為 deleted
// 錯誤說法:編譯器會隱式宣告
Empty* operator&();
const Empty* operator&() const;
// 正確:編譯器**不會**隱式宣告這兩個運算子
// 當對 Empty 物件使用 & 時,直接使用**內建運算子**
《Effective C++》條款 45 原文錯誤列出取址運算子。讀者回報後,Meyers 在勘誤表確認:
"A class declaring no operator& function(s) does NOT have them implicitly declared. Rather, compilers use the built-in address-of operator whenever '&' is applied to an object of that type. This behavior is technically not an application of a global operator& function. Rather, it is a use of a built-in operator."
operator&,會屏蔽內建取址,導致 &obj 回傳自訂類型,標準庫容器、智慧指標可能失效std::is_empty<Empty>::value == true 依賴無非靜態資料成員且無虛函數class Empty {};
Empty a;
Empty b = std::move(a); // 呼叫隱式移動建構子 (若符合條件)
Empty c;
c = std::move(b); // 呼叫隱式移動指派
隱式移動操作會逐成員移動。空類別無成員,故移動操作等同於無操作 (no-op),但仍參與多載解析。
#include <iostream>
#include <type_traits>
class Empty {};
int main() {
std::cout << "is_empty: " << std::is_empty<Empty>::value << '\n';
std::cout << "has default ctor: " << std::is_default_constructible<Empty>::value << '\n';
std::cout << "has copy ctor: " << std::is_copy_constructible<Empty>::value << '\n';
std::cout << "has move ctor: " << std::is_move_constructible<Empty>::value << '\n';
std::cout << "has copy assign: " << std::is_copy_assignable<Empty>::value << '\n';
std::cout << "has move assign: " << std::is_move_assignable<Empty>::value << '\n';
std::cout << "sizeof(Empty): " << sizeof(Empty) << '\n';
// 驗證取址運算子非成員
Empty e;
Empty* p = &e; // 使用內建 &
(void)p;
}
輸出 (C++17):
is_empty: 1
has default ctor: 1
has copy ctor: 1
has move ctor: 1
has copy assign: 1
has move assign: 1
sizeof(Empty): 1
| 說法 | 正確性 | 說明 |
|---|---|---|
| 空類別有 6 個隱式成員 | ❌ 錯誤 | 含取址運算子,出自舊版 Effective C++ 錯誤 |
| 空類別有 4 個隱式成員 (C++98) | ✅ 正確 | 預設建構、拷貝建構、拷貝指派、解構 |
| 空類別有 6 個隱式成員 (C++11+) | ⚠️ 部分正確 | 上述 4 個 + 移動建構 + 移動指派 (視條件) |
| 取址運算子是隱式成員 | ❌ 錯誤 | 使用內建運算子,非成員函數 |
| 自訂 operator& 會取代內建 | ✅ 正確 | 極度危險,破壞標準庫假設 |
「空類別有六大預設成員」是流傳久遠的錯誤迷思。依標準,**只有建構/解構/指派操作會被隱式宣告,取址運算子永遠使用內建版本**。理解此區別,不僅能在面試中加分,更能避免在實務中誤重載 operator& 導致難以診斷的標準庫相容性問題。