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

C++類別核心觀念與MFC編程規範全攻略:從構造析構到虛函數多態

     編輯:關於VC++

MFC建構於C++類別技術之上,若僅具C語言基礎,必須先建立正確的C++物件導向觀念。本文將以「鳥類」為贯穿範例,系統講解類別定義、構造/析構函數、存取權限、繼承與覆寫、虛函數多態機制,並總結MFC類別設計哲學與產業級C++編碼規範(匈牙利命名法、函數/類別/檔案組織原則)。

第一部分:C++類別核心觀念

什麼是類別?——資料與操作的封裝體

類別是使用者定義型別,將相關資料(成員變數)與操作(成員函數)封裝為邏輯整體,具備:

  • 封裝性:隱藏內部實作,僅暴露公用介面
  • 資料隱藏:透過 private/protected 控制存取
  • 抽象性:定義「是什麼」而非「怎麼做」

從結構體到類別:鳥類範例演進

階段 1:單純資料結構(類C風格)


class Aves {
public:
    char m_strHead[10];
    char m_strTrunk[10];
    char m_strCrura[10];
    char m_strWing[10];
    char m_strBowels[10];
};
// 用法:Aves bird; bird.m_strHead = "Head"; // 直接存取,無封裝

階段 2:加入構造函數——自動初始化


class Aves {
public:
    Aves() { // 構造函數:同名、無回傳型別
        strcpy(m_strHead, "Head");
        strcpy(m_strTrunk, "Trunk");
        // ...
    }
    // 成員變數...
};
// 用法:Aves bird; // 自動呼叫構造函數完成初始化
  • 構造函數在物件建立時自動呼叫(棧上物件進作用域、new 配置堆上物件)
  • 可多載:Aves()、Aves(const char* name) 等

階段 3:加入析構函數——資源釋放


class Aves {
public:
    Aves() { /* 分配資源 */ }
    ~Aves() { /* 釋放資源 */ } // 析構函數:波浪號開頭、無參數、無回傳
};
  • 析構函數在物件銷毀時自動呼叫:棧上物件離開作用域、delete 堆上物件
  • RAII原則:構造獲取資源、析構釋放資源,防止記憶體洩漏

階段 4:加入成員函數與存取控制


class Aves {
public:  // 公用介面:外部可存取
    Aves();
    ~Aves();
    void Tweet();
    void Run();
    void Fly();
    char m_strHead[10];
    char m_strWing[10];
    // ...

protected: // 保護成員:衍生類別可存取,外部不可
    char m_strBowels[10]; // 內臟:衍生類需知,外部不必知

private: // 私有成員:僅本類別內部可存取
    // 若無指定,class預設private,struct預設public
};

階段 5:this 指標與成員存取


void Aves::Run() {
    // 完整寫法
    cout << "I can run by " << this->m_strCrura << endl;
    // 簡寫(編譯器隱式加上this->)
    cout << "I can run by " << m_strCrura << endl;
}
  • this 型別為 Aves* const,指向當前物件
  • 非靜態成員函數隱含 this 參數

物件建立與生命週期

方式語法記憶體區域銷毀時機
自動物件Aves bird;Stack離開作用域(})
動態物件Aves* p = new Aves();Heapdelete p;
陣列Aves* arr = new Aves[10];Heapdelete[] arr;

關鍵:new 對應 delete,new[] 對應 delete[],型別必須匹配否則析構函數不會正確呼叫。

第二部分:繼承與多態

單一繼承:鴕鳥繼承鳥類


class Ostrich : public Aves { // public繼承:保持介面語意
public:
    void Tweet() override { cout << "Gugu...\n"; } // 覆寫
    void Fly() override { cout << "I can't fly!\n"; } // 覆寫
};
  • public 繼承 = 「是一種」關係,保留基類介面
  • 衍生類別自動擁有基類所有 non-private 成員
  • protected 成員對衍生類別可見,解決 private 不可見問題

虛函數與動態繫結——多態核心機制


class Aves {
public:
    virtual void Fly() { cout << "I can fly\n"; } // virtual關鍵字
    virtual void Tweet() { cout << "Jiji...\n"; }
};

class Ostrich : public Aves {
public:
    void Fly() override { cout << "I can't fly\n"; }
    void Tweet() override { cout << "Gugu...\n"; }
};

// 測試多態
void TestFly(Aves* pBird) { pBird->Fly(); } // 透過基類指標

int main() {
    Aves bird; 
    Ostrich ost;
    
    TestFly(&bird);  // 輸出: I can fly
    TestFly(&ost);   // 輸出: I can't fly  ← 動態繫結!
    
    // 直接呼叫
    Aves* p = &ost;
    p->Fly();        // 輸出: I can't fly  ← 關鍵差異!
}

虛函數表(vtable)機制

  • 含 virtual 函數的類別,編譯器產生 虛函數表(函數名→位址映射)
  • 每個物件隱含 vptr 指向其類別的 vtable
  • 呼叫虛函數時:p->vptr[vtable_index]() 間接跳轉,實現執行期綁定
  • 衍生類別覆寫虛函數 → 編譯器在其 vtable 中更新對應位址

多重繼承預告

COM開發大量使用多重繼承(一個類別實作多個介面),後續COM章節將詳細講解。

第三部分:MFC類別設計哲學

從Handle到物件的封裝演進

Win32 SDK風格MFC風格
HWND hWnd = CreateWindow(...);
ShowWindow(hWnd, SW_SHOW);
CloseWindow(hWnd);
CWnd wnd;
wnd.CreateWindow(...);
wnd.ShowWindow(SW_SHOW);
wnd.CloseWindow();
  • SDK:Handle為中心,函數圍繞Handle操作
  • MFC:物件為中心,Handle封裝為 m_hWnd 保護成員,方法成為物件行為
  • 所有MFC類別最終繼承自 CObject
  • 視窗相關類別繼承鏈:CWnd → CCmdTarget → CObject

關鍵MFC類別速覽

  • CWnd:所有視窗控制項基類(CButton、CEdit、CListBox...)
  • CDialog、CFrameWnd、CView、CMDIFrameWnd
  • 訊息映射、CRuntimeClass、動態建立機制詳見《MFC核心技術》、《C++物件模型》

第四部分:產業級C++編碼規範

命名規範:匈牙利標記法

規則:有意義的英文單字、駝峰式大小寫、常數全大寫(MAX_COUNT)

變數宣告原則

  1. 區域變數宣告於函數/區塊最前端
  2. 全域變數置於檔案最前端
  3. 常數用 const 而非 #define
  4. 輸入參數為指標時加 const 防誤改

函數設計原則

  1. 參數順序:輸出參數在前、輸入參數在後
  2. 全域函數加 Afx 前綴,動詞開頭(AfxGetMessage())
  3. 回傳值用於錯誤碼,實質資料用輸出參數回傳
  4. 函數開頭驗證參數合法性
  5. 函數長度 ≤ 50 行,超過則拆分
  6. 避免 static 區域變數(難測試、執行緒不安全)

類別組織原則

  1. 成員變數統一 m_ 前綴
  2. 宣告順序:public → protected → private,函數在前、變數在後
  3. 類別宣告不可初始化(int m_n = 0; 錯誤,須在構造函數初始化)
  4. 一個類別一對檔案:ClassName.h(宣告)、ClassName.cpp(實作),.cpp 首行 #include "ClassName.h"

格式與註解規範

  • if/for/while/do 必加大括號,即使單行
  • 一行一陳述式,勿壓行
  • 註解「為什麼」而非「做什麼」,複雜演算法、內嵌組語必註解
  • 預留擴充空間,介面設計考慮相容性

工程效能鐵律

70% 時間設計演算法架構 | 27% 時間寫文檔 | 1% 時間寫代碼 | 2% 時間除錯

  • 先規劃再編碼,避免反覆重構導致代碼混亂
  • 常用功能封裝為可復用類別(UI元件、資料存取層...)
  • 非必要不追求炫酷UI,核心邏輯優先

總結

掌握 構造/析構 → 存取控制 → 繼承/覆寫 → 虛函數多態 → RAII資源管理 五大支柱,即具備閱讀與撰寫MFC級C++代碼的基礎。配合嚴謹的編碼規範,能寫出可維護、可擴充、團隊協作友善的專業代碼。下一章將實戰解析 MFC對話框程式完整架構。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
前綴含義範例
m_類別成員m_nCount
_ 或 Afx全域變數/函數_g_hInstance, AfxGetApp()
bBOOLbVisible
hHandlehWnd
nintnCount
dwDWORDdwStyle
p/lp指標pObj, lpData
strCStringstrName
sz以null結尾字串szPath