C++ — 靜態繫結與動態繫結
靜態繫結與動態繫結
——————————————————————————————————
靜態繫結,動態繫結算是一個比較偏的知識點,這個也是我在Effective C++這本書當中學習到的. 我覺得很有必要寫一篇部落格記錄.
首先我們要知道靜態型別和動態型別的概念:
靜態型別:就是它在程式中被宣告時所採用的型別(或理解為型別指標或引用的字面型別),在編譯期確定;
動態型別:目前所指物件的型別。是在執行期決定的。物件的動態型別可以更改,但是靜態型別無法更改。
接下來我引用Effective C++這本書中的例子,幫助理解:
class Shape
{
public:
enum shapeColor{Red,Green,Blue};
//所有形狀都必須提供一個函式,同來繪出自己.
virtual void draw(shapeColor color = Red) const = 0;
...
};
class Rectangle : public Shape
{
public:
//注意,賦予不同的預設引數值,這真糟糕
virtual void draw(shapeColor color = Green) const;
};
class Circle : public Shape
{
public:
virtual void draw(shapeColor color) const;
//請注意,以上這麼寫則當客戶以物件呼叫此函式,一定要指定引數值.
//因為靜態繫結下這個函式並不從其base繼承預設引數值
//但若以指標(或reference)呼叫此函式,可以不指定引數值
//因為動態繫結下這個函式會從其base繼承預設引數值
......
};
Shape *ps; // ps的靜態型別為Shape*,它沒有動態型別,因為它尚未指向任何物件;
Shape *pc = new Circle; // pc的靜態型別為Shape*,它的動態型別為Circle*;
Shape *pr = new Rectangle; // pr的靜態型別為Shape*,它的動態型別為Rectangle*;
// 動態型別可以在程式執行過程中改變(通常是經由賦值動作):
ps = pc; // ps的動態型別如今是Circle*;
ps = pr; // ps的動態型別如今是Rectangle*;
現在我們來理解何為靜態繫結和動態繫結???
靜態繫結:又名前期繫結(eraly binding),繫結的是靜態型別,所對應的函式或屬性依賴於物件的靜態型別,發生在編譯期;
動態繫結:又名後期繫結(late binding),繫結的是動態型別,所對應的函式或屬性依賴於物件的動態型別,發生在執行期;
比如常見的,virtual函式是動態繫結,non-virtual函式是靜態繫結,預設引數值也是靜態繫結.Virtual函式系動態繫結而來,
意思是呼叫了一個virtual函式時,究竟呼叫那一份函式實現程式碼,取決於付出呼叫的那個物件的動態型別:
pc->draw(shape::Red); //呼叫Circle::draw(shape::Red)
pr->draw(shape::Red); //呼叫Rectangle::draw(shape::Red)
其實這些都是老掉牙的知識點,但是今天我們帶來了virtual函式不同的地方,預設值! virtual函式是動態繫結的,而預設引數
值為靜態繫結. 意思是你可能會在"呼叫一個定義與derived class內的virtual函式"的同時,卻使用base class為他所指定的預設
參數值.
pr->draw(); //呼叫Rectangle::draw(shape::Red)!
此例當中,pr的動態型別為Rectangle*,所以呼叫的是Rectangle的virtual函式,一如你所預料.Rectangle::draw函式的預設值應
該是Green,但由於pr的靜態型別為shape*,所以此一呼叫的預設引數值來自shape class而非Rectangle class!結局是這個函式調
用有這奇怪並且幾乎沒有人預料得到的組合,由shape class和Rectangle class的draw生命式各處一份力.以上事實不只侷限於
"ps,pc和pr都是指標"的情況;即使把指標換成references問題依然存在.重點在於draw是一個virtual函式,而它有個預設引數值在
derived class中被重新定義了.
為什麼C++堅持以這種乖張的方式來運作呢? 答案在於執行期效率. 如果預設引數值為動態繫結,編譯器就必須有某種方法在執行
期為virtual函式決定適當的引數預設值.這比目前實行的"在編譯器決定"的機制更慢而且更復雜.為了程式的執行速度和編譯器實
現上的簡易度,C++做了這樣的取捨,其結果就是你如今所享受的執行效率. 但是如果你重新定義了繼承而來的預設引數值,而且偏
偏在預設引數值上面出現bug,那麼你可能需要一個通宵都不一定調的出來.
相關文章
- 理解靜態繫結與動態繫結
- C++的動態繫結和靜態繫結C++
- java中的靜態繫結與動態繫結Java
- 後期靜態繫結
- 延遲靜態繫結——static
- php 後期靜態繫結PHP
- 介面(抽象類)與後期靜態繫結學習抽象
- JAVA動態繫結淺析Java
- 三、動態繫結屬性
- 對 PHP 後期靜態繫結的理解PHP
- vue 動態繫結 v-modelVue
- 動態繫結 input v-model
- 關於動態字串的繫結字串
- Vue select 繫結動態變數Vue變數
- Vue 動態繫結CSS樣式VueCSS
- 後期靜態繫結在PHP中的使用PHP
- 14 #### 方法分類與使用場景(繫結、靜態、類方法)
- 介面的繫結方案和動態SQLSQL
- class 和 style 資料動態繫結
- 域名繫結動態IP實戰案例
- 動態連結庫與靜態連結庫
- 動態生成的html元素繫結click事件HTML事件
- jQuery實現DOM元素事件動態繫結jQuery事件
- Vue 框架-05-動態繫結 css 樣式Vue框架CSS
- 構造器中呼叫動態繫結的方法
- 深入理解PHP物件導向之後期靜態繫結PHP物件
- Vue一個案例引發的動態元件與全域性事件繫結總結Vue元件事件
- 05-v-bind動態繫結class(物件語法)物件
- PHP 物件導向 (七)訪問物件的方式及後期靜態繫結PHP物件
- Hooks與事件繫結Hook事件
- 動態生成html元素繫結事件iphone失效問題解決HTML事件iPhone
- python-物件導向(繫結方法與非繫結方法)Python物件
- 使用 Hooks 簡化受控元件的狀態繫結Hook元件
- 【連結 1】與靜態連結庫連結
- 百度前端學院任務動態資料繫結(五)前端
- 延遲繫結與retdlresolve
- Vue Class與Style繫結Vue
- vue Class 與 Style 繫結Vue
- C/C++ Qt 資料庫與TreeView元件繫結C++QT資料庫View元件