q:
#include
using namespace std;
class base ;
// 乙個表示幾何形狀的類
class shape ;
class rectangle: public shape ;
class circle: public shape ;
用圖形來表示是下面這樣:
shape
// / /
/ /
rectangle circle
現在看看這些指標:
shape *ps; // 靜態型別 = shape*
shape *pc = new circle; // 靜態型別 = shape*
shape *pr = new rectangle; // 靜態型別 = shape*
這個例子中, ps, pc,和pr都被宣告為shape指標型別,所以它們都以此作為自己的靜態型別。注意,這和它們真的所指向的物件的型別絕對沒有關係 ---- 它們的靜態型別總是shape*。
物件的動態型別是由它當前所指的物件的型別決定的。即,物件的動態型別表示它將執行何種行為。上面的例子中,pc的動態型別是circle*,pr的動態型別是rectangle*。至於ps,實際上沒有動態型別,因為它(還)沒有指向任何物件。
動態型別,顧名思義,可以在程式執行時改變,典型的方法是通過賦值:
ps = pc; // ps的動態型別
// 現在是circle*
ps = pr; // ps的動態型別
// 現在是rectangle*
虛函式是動態繫結的,意思是說,虛函式通過哪個物件被呼叫,具體被呼叫的函式就由那個物件的動態型別決定:
pc->draw(red); // 呼叫circle::draw(red)
pr->draw(red); // 呼叫rectangle::draw(red)
我知道這些都是老掉牙的知識了,你當然也了解虛函式。(如果想知道它們是怎麼實現的,參見條款m24)但是,將虛函式和預設引數值結合起來分析就會產生問題,因為,如上所述,虛函式是動態繫結的,但預設引數是靜態繫結的。這意味著你最終可能呼叫的是乙個定義在派生類,但使用了基類中的預設引數值的虛函式:
pr->draw(); // 呼叫rectangle::draw(red)!
這種情況下,pr的動態型別是rectangle*,所以rectangle的虛函式被呼叫 ---- 正如我們所期望的那樣。rectangle::draw中,預設引數值是green。但是,由於pr的靜態型別是shape*,這個函式呼叫的引數值是從shape類中取得的,而不是rectangle類!所以結果將十分奇怪並且出人意料,因為這個呼叫包含了shape和rectangle類中draw的宣告的組合。你當然不希望自己的軟體以這種方式執行啦;至少,使用者不希望這樣,相信我。
不用說,ps, pc,和pr都是指標的事實和產生問題的原因無關。如果它們是引用,問題也會繼續存在。問題僅僅出在,draw是乙個虛函式,並且它的乙個預設引數在子類中被重新定義了。
為什麼c++堅持這種有違常規的做法呢?答案和執行效率有關。如果預設引數值被動態繫結,編譯器就必須想辦法為虛函式在執行時確定合適的預設值,這將比現在採用的在編譯階段確定預設值的機制更慢更複雜。做出這種選擇是想求得速度上的提高和實現上的簡便,所以大家現在才能感受得到程式執行的高效;當然,如果忽視了本條款的建議,就會帶來混亂。
虛函式預設引數的問題記錄
剛看了看專案裡的問題,對虛函式預設引數的問題有點兒遺忘,翻了翻資料 the result is i is 3 原因 為什麼c 堅持這種有違常規的做法呢?答案和執行效率有關。如果預設引數值被動態繫結,編譯器就必須想辦法為虛函式在執行時確定合適的預設值,這將比現在採用的在編譯階段確定預設值的機制更慢更複...
C 中 虛函式中的預設引數問題
原文 nwplei的部落格 當通過指標呼叫乙個物件的方法時,如果該方法是虛函式,則實際呼叫的是該例項的方法。當預設引數和虛函式一起出現的時候到底用哪個預設值呢?虛函式是動態繫結的,但是為了執行效率,預設引數是靜態繫結的。也就是 指標是哪種型別,就呼叫該型別對應的類中,該函式定義時的預設值。inclu...
C 中 虛函式中的預設引數問題
當通過指標呼叫乙個物件的方法時,如果該方法是虛函式,則實際呼叫的是該例項的方法。當預設引數和虛函式一起出現的時候到底用哪個預設值呢?虛函式是動態繫結的,但是為了執行效率,預設引數是靜態繫結的。也就是 指標是哪種型別,就呼叫該型別對應的類中,該函式定義時的預設值。include using names...