首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

C++ 三大設計準則:慎用虛函數、拒絕 || 技巧、純虛函數可有預設實作

     編輯:C++ 入門

前言:細節決定架構壽命

看似微小的語法選擇,長期積累決定程式碼是「資產」還是「負債」。分享三條血淚凝練的鐵律。

一、如無必要,勿增虛函數

反面教材:以虛函數表達靜態屬性


class Ball { virtual bool IsKickable() = 0; };
class Football  { bool IsKickable() override { return true; } };
class Basketball { bool IsKickable() override { return false; } };

問題:IsKickable 是球類的本質靜態屬性,不隨物件狀態改變,無需動態派發。虛函數帶來:vptr 佔用 8 位元組、間接呼叫開銷、vtable 膨脹、二進位相容性負擔。

正解:資料成員 + 非虛函數


class Ball {
protected:
    bool m_kickable;
public:
    bool IsKickable() const { return m_kickable; }  // 非虛、內聯、零開銷
};
class Football  : public Ball { public: Football()  : m_kickable(true)  {} };
class Basketball : public Ball { public: Basketball() : m_kickable(false) {} };

判斷準則:若派生類覆寫內容僅是 return 常數; 或存取固定資料成員,必為靜態屬性,勿用虛函數。

二、不要用 || 做複雜邏輯判斷

反模式:短路求值濫用


// 難以閱讀的單行斷言
assert(IsA() || IsB() || bOk);
// 邏輯等價於:(!IsA() && !IsB()) ⇒ bOk

維護者需心理模擬德摩根定律,極易誤讀。除錯時無法在中間條件設中斷點,覆蓋率分析也失真。

正解:直觀的 if-else


if (IsC()) {
    assert(bOk);  // 清楚表達:C 狀態下 bOk 必為真
}

或提煉具名輔助函數:bool IsValidState() { return IsA() || IsB() || bOk; } 並加註解。

三、純虛函數可提供預設實作

場景:抽象基類需強制派生類實作,但提供通用預設行為


class Base {
public:
    virtual ~Base() = 0;  // 純虛析構函數,使 Base 成為抽象類
};
Base::~Base() { printf("~Base()\n"); }  // 必須提供定義!派生類析構會呼叫

class Derived : public Base {
public:
    ~Derived() override { printf("~Derived()\n"); }
};

關鍵點:
1. = 0 只影響「可否實例化」,不影響「是否有函數體」。
2. 純虛析構函數必須提供定義,因為派生類析構鏈會隱式呼叫基類析構函數。
3. 同理可用於其他必須覆寫但有通用預設邏輯的虛函數(如 virtual void Initialize() = 0; 提供預設初始化流程)。

結語

虛函數用於「行為多型」,非「資料多型」;邏輯表達優先「人類可讀」而非「機器短碼」;純虛與實作並不互斥,善用語法特性表達設計意圖。三條準則,寫出經得起十年演進的程式碼。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved