概念
多態在代碼中指的就是“一個接口,多種實現”(相同的調用方法有不同的實現方式),屬於面向對象編程的核心概念。廣義的多態包括靜態多態和動態多態,其中靜態多態指的是編譯時就可以確認使用的接口,動態多態指的是運行時才能確定具體引用的接口。
靜態多態和動態多態本質上的區別在於什麼時候(編譯期間or運行期間)將函數實現與函數調用關聯起來。靜態多態在編譯期間就可以確定函數的調用地址併產生對應代碼,動態多態在運行時才能確定函數的調用地址。
實例
1. 靜態多態
靜態多態往往通過函數重載和泛型編程(模板)實現:
#include <iostream>
// int型的加法函數
int add(int a, int b) {
return a + b;
}
// double型的加法函數
double add(double a, double b) {
return a + b;
}
// 函數模板的加法函數
template <typename T> T add(T a, T b) {
return a + b;
}
int main() {
std::cout << add(1, 1) << std::endl; // 調用int型的加法函數
std::cout << add(1.2, 3.4) << std::endl; // 調用double型的加法函數
std::cout << add<char>('A', ' ') << std::endl; // 調用函數模板的加法函數, 輸出小寫字母a
}
編譯輸出:
$g++ -o main main.cpp
$./main
2
4.6
a
2. 動態多態
動態多態最常見的方法就是使用基類的指針(或引用)調用一個虛函數:
#include <iostream>
// 基類
class Base {
public:
virtual std::string foo() {
return "Base::foo()";
}
};
// 派生類
class Derived : public Base {
public:
std::string foo() override {
return "Derived::foo()";
}
};
int main() {
// pb靜態類型爲Base*, 動態類型Derived*
Base *pb = new Derived;
std::cout << pb->foo() << std::endl;
// rb靜態類型爲Base&, 動態類型爲Derived&
Base &rb = *(new Derived);
std::cout << rb.foo() << std::endl;
}
編譯輸出:
# override使用到了C++11新特性, 加上編譯參數-std=c++11
$g++ -o main -std=c++11 main.cpp
$./main
Derived::foo()
Derived::foo()
使用多態的原因
面向對象編程中封裝可以使得代碼模塊化,繼承可以擴展已存在的代碼,這兩者的本質都是爲了代碼重用。而多態的目的在於接口重用。靜態多態可以根據傳入不同的參數(不同參數個數或者不同參數類型)調用不同的實現,動態多態可以用相同的代碼處理基類和派生類對象,運行時再根據基類的引用(或指針)所綁定對象的真實類型來調用不同的實現。
和封裝繼承一樣,多態不僅可以改善代碼的組織結構和可讀性,還可以讓程序更加具有可擴展性。
Reference
[1] https://zhuanlan.zhihu.com/p/37340242
[2] https://blog.csdn.net/qq_43461641/article/details/100139924
[3] https://blog.csdn.net/zcxwww/article/details/51303928
[4] https://www.runoob.com/cplusplus/cpp-polymorphism.html
[5] https://blog.csdn.net/qq_37934101/article/details/81365449