初學 C++ 時,純虛函數、抽象類、工廠模式的結合常導致編譯錯誤或運行時崩潰。本文針對一段典型錯誤代碼進行逐行分析,並給出現代 C++ 最佳實踐修正方案。
// 基類
virtual void talk() const = 0; // 帶 const
// 派生類
void talk() { ... } // 缺少 const → 隱藏而非覆寫,導致派生類仍為抽象類
修正:派生類必須保持完全相同的簽名,包含 const 限定符。
Toy* getToy(string& type) {
if (type == "Dog") { Dog *d; return d; } // d 未初始化,返回野指針
if (type == "Cat") { Cat *c; return c; }
}
問題:
new 分配內存,返回懸空指針。ToyFactory *tf = new ToyFactory(); // 正確
ToyFactory tf = new ToyFactory(); // 錯誤:new 返回指針,不能賦值給值類型
#include <iostream>
#include <string>
#include <memory> // unique_ptr
using namespace std;
class Toy {
public:
virtual void talk() const = 0;
virtual ~Toy() = default; // 虛析構函數必須
};
class Dog : public Toy {
public:
void talk() const override { cout << "Wow" << endl; }
};
class Cat : public Toy {
public:
void talk() const override { cout << "Meow" << endl; }
};
class ToyFactory {
public:
// 返回 unique_ptr 自動管理生命週期
unique_ptr<Toy> getToy(const string& type) {
if (type == "Dog") return make_unique<Dog>();
if (type == "Cat") return make_unique<Cat>();
return nullptr;
}
};
int main() {
string type = "Dog";
ToyFactory factory; // 棧上分配,無需 new
auto toy = factory.getToy(type);
if (toy) toy->talk();
return 0;
}
| 項目 | 原寫法 | 現代寫法 | 優勢 |
|---|---|---|---|
| 虛函數簽名 | 缺少 const | override + const | 編譯期檢查,防止隱藏 |
| 內存管理 | 裸指針 + 手動 new/delete | unique_ptr + make_unique | RAII,零內存洩漏 |
| 工廠對象 | new ToyFactory() | 棧上 ToyFactory factory | 自動析構,异常安全 |
| 參數傳遞 | string& | const string& | 接受臨時對象,語義更清晰 |
C++ 多態的核心在於虛函數簽名完全一致與所有權語義明確。採用智能指針、override 關鍵字、值語義工廠,能從語言層面消除一大類資源管理 Bug,寫出更健壯的代碼。