C++ 通過虛函數實現多態:「無論發送消息的對象屬於何類,均發送同一形式消息,處理方式隨接收對象而異」。在類層次結構中,可對任意派生類對象的同名函數調用,具體處理隨所屬類而變。虛函數是可在派生類中重新定義賦予新功能的成員函數。
class Base {
public:
virtual void Fun(); // 基類聲明虛函數
};
class Derived : public Base {
public:
virtual void Fun(); // 派生類重定義(可加 virtual,也可不加)
};
class A { public: virtual void fun0() {} };
int main() { A a; cout << sizeof(a); } // 輸出 4 (32位系統指針大小)
增加 virtual void fun1(),sizeof(A) 仍為 4。因為虛函數地址存放在虛函數表(VTABLE)中,對象僅包含一個指向 VTABLE 的指針(vptr)。
class A { public: void fun0() {} }; // 非虛
int main() { A a; cout << sizeof(a); } // 輸出 1 (空類最小佔 1 字節)
class A { public: virtual void fun0() {}; int a; int b; };
// sizeof(A) = 12 (vptr 4 + int a 4 + int b 4,可能含對齊填充)

圖一:對象包含 vptr 指向虛函數表
class A { public: virtual void f() {} };
class B { public: virtual void f() {} };
class C { public: virtual void f() {} };
class Drive : public A, public B, public C {};
// sizeof(Drive) = 12 (三個基類各有一個 vptr)

圖三:多重繼承包含多個 vptr
class A { public: virtual void f() { cout << "A::f"; } };
class B : public A { public: virtual void f() { cout << "B::f"; } };
class C : public A { public: virtual void f() { cout << "C::f"; } };
class D : public C { public: virtual void f() { cout << "D::f"; } };
int main() {
A a; B b; C c; D d;
a.f(); b.f(); c.f(); d.f(); // 分別輸出 A::f B::f C::f D::f
}
注意:多態 ≠ 函數重載。
void test(A* a) { a->f(); } // 參數為基類指針
int main() {
B* b = new B; C* c = new C;
char choice;
do {
cout << "type B or C: "; cin >> choice;
if (choice == 'b') test(b);
else if (choice == 'c') test(c);
} while(1);
}
運行時根據實際對象類型調用對應虛函數,即動態綁定。若去掉 virtual,則為靜態綁定(調用基類版本)。
class A {
public:
virtual void fun() { cout << "A::fun"; }
void show() { fun(); } // 基類內部調用虛函數
};
class B : public A {
public:
virtual void fun() { cout << "B::fun"; }
};
int main() {
A a; a.show(); // 輸出 A::fun
// 若 A* pa = new B; pa->show(); 則輸出 B::fun
}
利用虛函數,基類可調用派生類覆寫的函數。非虛函數則無法實現此行為。
static_cast 顯式轉換,轉換後可調用基類與派生類成員。