MFC建構於C++類別技術之上,若僅具C語言基礎,必須先建立正確的C++物件導向觀念。本文將以「鳥類」為贯穿範例,系統講解類別定義、構造/析構函數、存取權限、繼承與覆寫、虛函數多態機制,並總結MFC類別設計哲學與產業級C++編碼規範(匈牙利命名法、函數/類別/檔案組織原則)。
類別是使用者定義型別,將相關資料(成員變數)與操作(成員函數)封裝為邏輯整體,具備:
private/protected 控制存取
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"; // 直接存取,無封裝
class Aves {
public:
Aves() { // 構造函數:同名、無回傳型別
strcpy(m_strHead, "Head");
strcpy(m_strTrunk, "Trunk");
// ...
}
// 成員變數...
};
// 用法:Aves bird; // 自動呼叫構造函數完成初始化
new 配置堆上物件)Aves()、Aves(const char* name) 等
class Aves {
public:
Aves() { /* 分配資源 */ }
~Aves() { /* 釋放資源 */ } // 析構函數:波浪號開頭、無參數、無回傳
};
delete 堆上物件
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
};
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(); | Heap | delete p; |
| 陣列 | Aves* arr = new Aves[10]; | Heap | delete[] 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 ← 關鍵差異!
}
virtual 函數的類別,編譯器產生 虛函數表(函數名→位址映射)vptr 指向其類別的 vtablep->vptr[vtable_index]() 間接跳轉,實現執行期綁定COM開發大量使用多重繼承(一個類別實作多個介面),後續COM章節將詳細講解。
| Win32 SDK風格 | MFC風格 |
|---|---|
HWND hWnd = CreateWindow(...); ShowWindow(hWnd, SW_SHOW); CloseWindow(hWnd); |
CWnd wnd; wnd.CreateWindow(...); wnd.ShowWindow(SW_SHOW); wnd.CloseWindow(); |
m_hWnd 保護成員,方法成為物件行為CObjectCWnd → CCmdTarget → CObjectCWnd:所有視窗控制項基類(CButton、CEdit、CListBox...)CDialog、CFrameWnd、CView、CMDIFrameWndCRuntimeClass、動態建立機制詳見《MFC核心技術》、《C++物件模型》| 前綴 | 含義 | 範例 |
|---|---|---|
m_ | 類別成員 | m_nCount |
_ 或 Afx | 全域變數/函數 | _g_hInstance, AfxGetApp() |
b | BOOL | bVisible |
h | Handle | hWnd |
n | int | nCount |
dw | DWORD | dwStyle |
p/lp | 指標 | pObj, lpData |
str | CString | strName |
sz | 以null結尾字串 | szPath |