多型(Polymorphism)
1. 什麼是多型
概念:多型是指在不同的上下文中,相同的操作或函式呼叫可能會產生不同的行為。它允許開發者編寫出更通用、更靈活的程式碼。
原理:多型主要透過虛擬函式和函式過載實現。它使得函式呼叫可以根據呼叫物件的實際型別來決定執行哪個函式。
用法:基類中宣告虛擬函式,派生類重寫這些虛擬函式。
案例程式碼:
class Animal {
public:
virtual void speak() {
cout << "Animal speaks" << endl;
}
};
class Dog : public Animal {
public:
void speak() override {
cout << "Dog barks" << endl;
}
};
class Cat : public Animal {
public:
void speak() override {
cout << "Cat meows" << endl;
}
};
void makeSound(Animal& animal) {
animal.speak(); // 多型呼叫
}
int main() {
Dog dog;
Cat cat;
makeSound(dog); // 輸出 Dog barks
makeSound(cat); // 輸出 Cat meows
return 0;
}
2. 多型分類
編譯時多型:
- 強制多型(也稱為靜態多型):透過函式過載和運算子過載實現,編譯器在編譯時確定呼叫哪個函式。
- 過載多型:透過函式過載實現,編譯器根據函式簽名(函式名和引數列表)來決定呼叫哪個函式。
- 引數化多型:透過模板實現,允許在編譯時根據模板引數生成不同的函式或類例項。
執行時多型:
- 包含多型(也稱為動態多型):透過虛擬函式實現,執行時根據物件的實際型別來決定呼叫哪個函式。
3. 編譯時多型:早繫結
概念:編譯時多型也稱為早繫結,因為函式呼叫的繫結在編譯時就已經確定。
原理:編譯器根據函式簽名或過載決議來決定呼叫哪個函式。
用法:函式過載、運算子過載和模板。
案例程式碼(函式過載):
void print(int i) {
cout << "Printing int: " << i << endl;
}
void print(double f) {
cout << "Printing double: " << f << endl;
}
int main() {
print(5); // 編譯時確定呼叫 print(int)
print(5.0); // 編譯時確定呼叫 print(double)
return 0;
}
4. 執行時多型:晚繫結
概念:執行時多型也稱為晚繫結,因為函式呼叫的繫結在執行時才確定。
原理:透過虛擬函式表(vtable)和虛擬函式指標(vptr)實現。每個包含虛擬函式的類都有一個虛擬函式表,物件會包含一個指向該表的指標。
用法:在基類中宣告虛擬函式,在派生類中重寫這些虛擬函式。
案例程式碼(虛擬函式):
class Base {
public:
virtual void func() {
cout << "Base::func()" << endl;
}
};
class Derived : public Base {
public:
void func() override {
cout << "Derived::func()" << endl;
}
};
int main() {
Base* b = new Derived();
b->func(); // 執行時確定呼叫 Derived::func()
delete b;
return 0;
}
多型是物件導向程式設計的一個重要特性,它提供了一種方式,使得相同的介面可以表現出不同的行為,這使得程式碼更加靈活和可擴充套件。