| 語法 | 調用構造函數 | 創建對象? | 備註 |
|---|---|---|---|
Cat Frisky; | 默認構造函數 Cat() | ✅ 是 | **最常用**,無參初始化 |
Cat Frisky(); | 默認構造函數 Cat() | ✅ 是 | **C++ 最令人困惑的語法** — 實際是函數聲明!(見下文) |
Cat Frisky(x, y); | 匹配參數的構造函數 | ✅ 是 | 顯式傳參初始化 |
Cat Frisky(); 是函數聲明!class Cat {
public:
Cat() { std::cout << "Constructor\n"; }
void meow() { std::cout << "Meow\n"; }
};
int main() {
Cat Frisky(); // ❌ 這不是創建對象!是聲明一個返回 Cat 的無參函數 Frisky
// Frisky.meow(); // 編譯錯誤:Frisky 是函數,非對象
Cat Frisky2; // ✅ 正確創建對象
Frisky2.meow(); // 輸出 Meow
}
這是 C++ 經典的 **Most Vexing Parse(最令人惱人的解析)**。
C++ 語法規定:**如果一個聲明既可以解釋為對象定義,也可以解釋為函數聲明,則優先解析為函數聲明。**
Cat Frisky(); → 無參數 → 既可視為「調用默認構造函數創建對象」,也可視為「聲明無參函數 Frisky 返回 Cat」 → 編譯器選擇後者。Cat Frisky; → 無括號 → **只能**是對象定義。Cat Frisky(x, y); → 有參數表達式 → **只能**是對象定義(函數聲明參數需類型名)。Cat Frisky{}; // ✅ 清楚創建對象,調用默認構造
Cat Frisky{x, y}; // ✅ 列表初始化,調用對應構造
Cat Frisky = Cat(); // ✅ 臨時對象移動/拷貝(通常優化掉)
Cat (Frisky); // ✅ 額外括號使其成為對象聲明
Cat Frisky = Cat(); // ✅ 拷貝初始化語法
-Wvexing-parse、MSVC /Wall 會提示此問題。Type name; → **對象**(默認構造)Type name(); → **函數聲明**(陷阱!)Type name(args); → **對象**(帶參構造)Type name{args}; → **對象**(統一初始化,推薦)見到 Type name(); 直接改成 Type name{};,告別最令人惱人的解析。