C++ 動态綁定
C++ 的虛函數 + 派生類對象及派生類到基類的類型轉換 共同完成了C++ 面向對象程式設計的三個基本概念之一--動态綁定。
同樣一段代碼運作時才能決定運作的具體函數是哪個(相對于編譯時就能确定而言),這個概念在C++ 中稱為動态綁定或運作時綁定(run-time binding)。
例如,定義下面一個接口用于列印書籍的總價格,這個接口既可以用于列印沒有折扣的書籍價格(基類 Quote 定義的對象),也可以列印有折扣的書籍價格(派生類 Bulk_quote 定義的對象)。
至于,item.net_price() 到底調用基類中的net_price()還是派生類中的net_price()取決于 print_total() 這個函數運作時的實參, const Quote &item 這個引用是基類定義的對象還是派生類定義的對象。
double print_total(const Quote &item, size_t n) {
double ret = item.net_price(n);
cout << "Total: " << ret << endl;
return ret;
}
基類如果希望派生類覆寫自己定義的某個函數,需要通過加上virtual 關鍵字,聲明為虛函數。
如果基類把一個函數聲明為虛函數,則該函數在派生類中隐式的也是虛函數。
動态綁定還用到一個概念就是派生類對象以及派生類到基類的類型轉換。
正是因為派生類對象中含有與其基類對應的部分,C++ 能将派生類的對象當成基類對象來使用,也可以将基類的指針或引用綁定到派生類對象的基類部分上。
如:
Quote item; // 基類對象
Bulk_quote bulk; // 派生類對象
Quote *p = &item; // p指向Quote 對象
p = &bulk; // p 指向bulk 的Quote部分
Quote &r = bulk; // r 綁定到bulk 的Quote 部分
如果基類中某個函數沒有被聲明為虛函數,派生類中也定義了同原型的函數的話,通過基類指針通路派生類定義的對象,調用的函數是基類中的定義,而不是派生類中的定義。
這也是增加一個 virtual 關鍵字的原因所在。
#include <iostream>
using namespace std;
#define VIRTUAL_FUNC
// Base class defination
class Quote {
public:
Quote() = default;
Quote(const std::string &book, double sales_price) :
bookNo(book), price(sales_price) {}
std::string isbn() const {
return bookNo;
}
#if defined (VIRTUAL_FUNC)
virtual double net_price(std::size_t n) const {
cout << "Quote" << endl;
return n * price;
}
#else
virtual double net_price(std::size_t n) const = 0;
#endif
virtual ~Quote() = default;
private:
std::string bookNo;
protected:
double price;
};
// Derived class defination
class Bulk_quote: public Quote {
public:
Bulk_quote()= default;
//Bulk_quote(const std::string &book, double sales_price, std::size_t qty, double dis);
Bulk_quote(const std::string &book, double sales_price, std::size_t qty, double dis):min_qty(qty), discount(dis), Quote(book, sales_price) { }
// double net_price(std::size_t n) const {
//cout << "hello" << endl;
// }
double net_price(std::size_t n) const {
cout << "Bulk_quote" << endl;
return n * price * discount;
}
private:
std::size_t min_qty;
double discount;
};
double print_total(const Quote &item, size_t n) {
double ret = item.net_price(n);
cout << "Total: " << ret << endl;
return ret;
}
//Quote item;
Quote basic_item("0-123", 10);
Bulk_quote item("0-123", 10, 3, 0.80);
Quote *p_item = &basic_item;
Quote *q_item = &item;
//Bulk_quote *q_item = &item;
int main() {
cout << print_total(*p_item, 5) << endl;
cout << print_total(*q_item, 5) << endl;
return 0;
}
運作結果:
Quote
Total: 50
50
Bulk_quote
Total: 40
40