執行時多型
1. 虛擬函式重寫
虛擬函式重寫是指在派生類中重新定義基類中已宣告為虛擬函式的函式。
虛擬函式重寫的工作原理:
- C++透過虛擬函式表(vtable)和虛表指標(vptr)實現執行時多型。
- 每個具有虛擬函式的類都有一個虛擬函式表,該表包含指向類中所有已定義虛擬函式的指標。
- 物件中包含一個指向該表的指標,稱為虛表指標,它指向物件所屬類的虛擬函式表。
虛擬函式表:
- 一個類如果有虛擬函式,編譯器會為該類生成一個虛擬函式表,表中包含指向類中所有虛擬函式的指標。
虛表指標:
- 每個物件都有一個虛表指標,它是一個指向類虛擬函式表的指標。
多個派生類是否共享基類的虛擬函式表:
- 不共享。每個類都有自己的虛擬函式表,即使是從基類繼承的虛擬函式,派生類的虛擬函式表也會包含這些函式的條目。
類的多個物件是否共享類的虛擬函式表:
- 是的,類的多個物件共享同一個類的虛擬函式表,但每個物件都有自己的虛表指標,指向同一個表。
案例程式碼:
class Base {
public:
virtual void show() {
cout << "Base show" << endl;
}
virtual ~Base() {}
};
class Derived : public Base {
public:
void show() override {
cout << "Derived show" << endl;
}
~Derived() {}
};
void func(Base* b) {
b->show(); // 執行時多型
}
int main() {
Base* b = new Derived();
func(b); // 輸出 Derived show
delete b;
return 0;
}
2. 純虛擬函式
純虛擬函式是在基類中宣告但沒有定義的虛擬函式,它要求派生類必須提供具體的實現。
案例程式碼:
class Shape {
public:
virtual void draw() const = 0; // 純虛擬函式
};
class Circle : public Shape {
public:
void draw() const override {
cout << "Drawing a circle" << endl;
}
};
int main() {
Shape* shape = new Circle();
shape->draw(); // 輸出 Drawing a circle
delete shape;
return 0;
}
3. 抽象類
抽象類是包含至少一個純虛擬函式的類。它不能被直接例項化,但可以作為其他類的基類。
案例程式碼:
class Animal {
public:
virtual void speak() const = 0; // 純虛擬函式
};
class Dog : public Animal {
public:
void speak() const override {
cout << "Woof!" << endl;
}
};
int main() {
// Animal a; // 錯誤:Animal是抽象類,不能例項化
Dog d; // 正確:Dog是非抽象類,可以例項化
d.speak(); // 輸出 Woof!
return 0;
}
4. 虛析構
虛析構是宣告為虛的解構函式,它確保在刪除基類指標時能夠呼叫正確的解構函式。
案例程式碼:
class Base {
public:
virtual ~Base() {
cout << "Base destructor" << endl;
}
};
class Derived : public Base {
public:
~Derived() {
cout << "Derived destructor" << endl;
}
};
int main() {
Base* b = new Derived();
delete b; // 呼叫 Derived 的解構函式,然後呼叫 Base 的解構函式
return 0;
}
在上述程式碼中,即使透過基類指標刪除派生類物件,也會按正確的順序呼叫派生類和基類的解構函式。這是透過虛解構函式實現的,它確保了正確的資源清理。