国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

C++中的虛函數(shù)(virtual function)(1)

2019-11-17 05:02:11
字體:
供稿:網(wǎng)友
一.簡介

虛函數(shù)是C++中用于實(shí)現(xiàn)多態(tài)(polymorphism)的機(jī)制。核心理念就是通過基類訪問派生類定義的函數(shù)。假設(shè)我們有下面的類層次:

class A

{

public:

virtual void foo() { cout << "A::foo() is called" << endl;}

};

class B: public A

{

public:

virtual void foo() { cout << "B::foo() is called" << endl;}

};

那么,在使用的時候,我們可以:

A * a = new B();

a->foo(); // 在這里,a雖然是指向A的指針,但是被調(diào)用的函數(shù)(foo)卻是B的!

這個例子是虛函數(shù)的一個典型應(yīng)用,通過這個例子,也許你就對虛函數(shù)有了一些概念。它虛就虛在所謂“推遲聯(lián)編”或者“動態(tài)聯(lián)編”上,一個類函數(shù)的調(diào)用并不是在編譯時刻被確定的,而是在運(yùn)行時刻被確定的。由于編寫代碼的時候并不能確定被調(diào)用的是基類的函數(shù)還是哪個派生類的函數(shù),所以被成為“虛”函數(shù)。虛函數(shù)只能借助于指針或者引用來達(dá)到多態(tài)的效果,假如是下面這樣的代碼,則雖然是虛函數(shù),但它不是多態(tài)的:

class A

{

public:

virtual void foo();

};

class B: public A

{

virtual void foo();

};

void bar()

{

A a;

a.foo(); // A::foo()被調(diào)用

}

1.1 多態(tài) 在了解了虛函數(shù)的意思之后,再考慮什么是多態(tài)就很輕易了。仍然針對上面的類層次,但是使用的方法變的復(fù)雜了一些:

void bar(A * a)

{

a->foo(); // 被調(diào)用的是A::foo() 還是B::foo()?

}

因?yàn)閒oo()是個虛函數(shù),所以在bar這個函數(shù)中,只根據(jù)這段代碼,無從確定這里被調(diào)用的是A::foo()還是B::foo(),但是可以肯定的說:假如a指向的是A類的實(shí)例,則A::foo()被調(diào)用,假如a指向的是B類的實(shí)例,則B::foo()被調(diào)用。

這種同一代碼可以產(chǎn)生不同效果的特點(diǎn),被稱為“多態(tài)”。

1.2 多態(tài)有什么用?多態(tài)這么神奇,但是能用來做什么呢?這個命題我難以用一兩句話概括,一般的C++教程(或者其它面向?qū)ο笳Z言的教程)都用一個畫圖的例子來展示多態(tài)的用途,我就不再重復(fù)這個例子了,假如你不知道這個例子,隨便找本書應(yīng)該都有介紹。我試圖從一個抽象的角度描述一下,回頭再結(jié)合那個畫圖的例子,也許你就更輕易理解。

在面向?qū)ο蟮木幊讨校紫葧槍?shù)據(jù)進(jìn)行抽象(確定基類)和繼續(xù)(確定派生類),構(gòu)成類層次。這個類層次的使用者在使用它們的時候,假如仍然在需要基類的時候?qū)戓槍惖拇a,在需要派生類的時候?qū)戓槍ε缮惖拇a,就等于類層次完全暴露在使用者面前。假如這個類層次有任何的改變(增加了新類),都需要使用者“知道”(針對新類寫代碼)。這樣就增加了類層次與其使用者之間的耦合,有人把這種情況列為程序中的“bad smell”之一。

多態(tài)可以使程序員脫離這種窘境。再回頭看看1.1中的例子,bar()作為A-B這個類層次的使用者,它并不知道這個類層次中有多少個類,每個類都叫什么,但是一樣可以很好的工作,當(dāng)有一個C類從A類派生出來后,bar()也不需要“知道”(修改)。這完全歸功于多態(tài)--編譯器針對虛函數(shù)產(chǎn)生了可以在運(yùn)行時刻確定被調(diào)用函數(shù)的代碼。

1.3 如何“動態(tài)聯(lián)編” 編譯器是如何針對虛函數(shù)產(chǎn)生可以再運(yùn)行時刻確定被調(diào)用函數(shù)的代碼呢?也就是說,虛函數(shù)實(shí)際上是如何被編譯器處理的呢?Lippman在深度探索C++對象模型[1]中的不同章節(jié)講到了幾種方式,這里把“標(biāo)準(zhǔn)的”方式簡單介紹一下。

我所說的“標(biāo)準(zhǔn)”方式,也就是所謂的“VTABLE”機(jī)制。編譯器發(fā)現(xiàn)一個類中有被聲明為virtual的函數(shù),就會為其搞一個虛函數(shù)表,也就是VTABLE。VTABLE實(shí)際上是一個函數(shù)指針的數(shù)組,每個虛函數(shù)占用這個數(shù)組的一個slot。一個類只有一個VTABLE,不管它有多少個實(shí)例。派生類有自己的VTABLE,但是派生類的VTABLE與基類的VTABLE有相同的函數(shù)排列順序,同名的虛函數(shù)被放在兩個數(shù)組的相同位置上。在創(chuàng)建類實(shí)例的時候,編譯器還會在每個實(shí)例的內(nèi)存布局中增加一個vptr字段,該字段指向本類的VTABLE。通過這些手段,編譯器在看到一個虛函數(shù)調(diào)用的時候,就會將這個調(diào)用改寫,針對1.1中的例子:

void bar(A * a)

{

a->foo();

}

會被改寫為:

void bar(A * a)

{

(a->vptr[1])();

}

因?yàn)榕缮惡突惖膄oo()函數(shù)具有相同的VTABLE索引,而他們的vptr又指向不同的VTABLE,因此通過這樣的方法可以在運(yùn)行時刻決定調(diào)用哪個foo()函數(shù)。

雖然實(shí)際情況遠(yuǎn)非這么簡單,但是基本原理大致如此。

1.4 overload和override 虛函數(shù)總是在派生類中被改寫,這種改寫被稱為“override”。我經(jīng)常混淆“overload”和“override”這兩個單詞。但是隨著各類C++的書越來越多,后來的程序員也許不會再犯我犯過的錯誤了。但是我打算澄清一下:

override是指派生類重寫基類的虛函數(shù),就象我們前面B類中重寫了A類中的foo()函數(shù)。重寫的函數(shù)必須有一致的參數(shù)表和返回值(C++標(biāo)準(zhǔn)答應(yīng)返回值不同的情況,這個我會在“語法”部分簡單介紹,但是很少編譯器支持這個feature)。這個單詞好象一直沒有什么合適的中文詞匯來對應(yīng),有人譯為“覆蓋”,還貼切一些。

overload約定成俗的被翻譯為“重載”。是指編寫一個與已有函數(shù)同名但是參數(shù)表不同的函數(shù)。例如一個函數(shù)即可以接受整型數(shù)作為參數(shù),也可以接受浮點(diǎn)數(shù)作為參數(shù)。一.簡介


虛函數(shù)是C++中用于實(shí)現(xiàn)多態(tài)(polymorphism)的機(jī)制。核心理念就是通過基類訪問派生類定義的函數(shù)。假設(shè)我們有下面的類層次:

class A

{

public:

virtual void foo() { cout << "A::foo() is called" << endl;}

};

class B: public A

{

public:

virtual void foo() { cout << "B::foo() is called" << endl;}

};

那么,在使用的時候,我們可以:

A * a = new B();

a->foo(); // 在這里,a雖然是指向A的指針,但是被調(diào)用的函數(shù)(foo)卻是B的!

這個例子是虛函數(shù)的一個典型應(yīng)用,通過這個例子,也許你就對虛函數(shù)有了一些概念。它虛就虛在所謂“推遲聯(lián)編”或者“動態(tài)聯(lián)編”上,一個類函數(shù)的調(diào)用并不是在編譯時刻被確定的,而是在運(yùn)行時刻被確定的。由于編寫代碼的時候并不能確定被調(diào)用的是基類的函數(shù)還是哪個派生類的函數(shù),所以被成為“虛”函數(shù)。虛函數(shù)只能借助于指針或者引用來達(dá)到多態(tài)的效果,假如是下面這樣的代碼,則雖然是虛函數(shù),但它不是多態(tài)的:

class A

{

public:

virtual void foo();

};

class B: public A

{

virtual void foo();

};

void bar()

{

A a;

a.foo(); // A::foo()被調(diào)用

}

1.1 多態(tài) 在了解了虛函數(shù)的意思之后,再考慮什么是多態(tài)就很輕易了。仍然針對上面的類層次,但是使用的方法變的復(fù)雜了一些:

void bar(A * a)

{

a->foo(); // 被調(diào)用的是A::foo() 還是B::foo()?

}

因?yàn)閒oo()是個虛函數(shù),所以在bar這個函數(shù)中,只根據(jù)這段代碼,無從確定這里被調(diào)用的是A::foo()還是B::foo(),但是可以肯定的說:假如a指向的是A類的實(shí)例,則A::foo()被調(diào)用,假如a指向的是B類的實(shí)例,則B::foo()被調(diào)用。

這種同一代碼可以產(chǎn)生不同效果的特點(diǎn),被稱為“多態(tài)”。

1.2 多態(tài)有什么用?多態(tài)這么神奇,但是能用來做什么呢?這個命題我難以用一兩句話概括,一般的C++教程(或者其它面向?qū)ο笳Z言的教程)都用一個畫圖的例子來展示多態(tài)的用途,我就不再重復(fù)這個例子了,假如你不知道這個例子,隨便找本書應(yīng)該都有介紹。我試圖從一個抽象的角度描述一下,回頭再結(jié)合那個畫圖的例子,也許你就更輕易理解。

在面向?qū)ο蟮木幊讨校紫葧槍?shù)據(jù)進(jìn)行抽象(確定基類)和繼續(xù)(確定派生類),構(gòu)成類層次。這個類層次的使用者在使用它們的時候,假如仍然在需要基類的時候?qū)戓槍惖拇a,在需要派生類的時候?qū)戓槍ε缮惖拇a,就等于類層次完全暴露在使用者面前。假如這個類層次有任何的改變(增加了新類),都需要使用者“知道”(針對新類寫代碼)。這樣就增加了類層次與其使用者之間的耦合,有人把這種情況列為程序中的“bad smell”之一。

多態(tài)可以使程序員脫離這種窘境。再回頭看看1.1中的例子,bar()作為A-B這個類層次的使用者,它并不知道這個類層次中有多少個類,每個類都叫什么,但是一樣可以很好的工作,當(dāng)有一個C類從A類派生出來后,bar()也不需要“知道”(修改)。這完全歸功于多態(tài)--編譯器針對虛函數(shù)產(chǎn)生了可以在運(yùn)行時刻確定被調(diào)用函數(shù)的代碼。

1.3 如何“動態(tài)聯(lián)編” 編譯器是如何針對虛函數(shù)產(chǎn)生可以再運(yùn)行時刻確定被調(diào)用函數(shù)的代碼呢?也就是說,虛函數(shù)實(shí)際上是如何被編譯器處理的呢?Lippman在深度探索C++對象模型[1]中的不同章節(jié)講到了幾種方式,這里把“標(biāo)準(zhǔn)的”方式簡單介紹一下。

我所說的“標(biāo)準(zhǔn)”方式,也就是所謂的“VTABLE”機(jī)制。編譯器發(fā)現(xiàn)一個類中有被聲明為virtual的函數(shù),就會為其搞一個虛函數(shù)表,也就是VTABLE。VTABLE實(shí)際上是一個函數(shù)指針的數(shù)組,每個虛函數(shù)占用這個數(shù)組的一個slot。一個類只有一個VTABLE,不管它有多少個實(shí)例。派生類有自己的VTABLE,但是派生類的VTABLE與基類的VTABLE有相同的函數(shù)排列順序,同名的虛函數(shù)被放在兩個數(shù)組的相同位置上。在創(chuàng)建類實(shí)例的時候,編譯器還會在每個實(shí)例的內(nèi)存布局中增加一個vptr字段,該字段指向本類的VTABLE。通過這些手段,編譯器在看到一個虛函數(shù)調(diào)用的時候,就會將這個調(diào)用改寫,針對1.1中的例子:

void bar(A * a)

{

a->foo();

}

會被改寫為:

void bar(A * a)

{

(a->vptr[1])();

}

因?yàn)榕缮惡突惖膄oo()函數(shù)具有相同的VTABLE索引,而他們的vptr又指向不同的VTABLE,因此通過這樣的方法可以在運(yùn)行時刻決定調(diào)用哪個foo()函數(shù)。

雖然實(shí)際情況遠(yuǎn)非這么簡單,但是基本原理大致如此。

1.4 overload和override 虛函數(shù)總是在派生類中被改寫,這種改寫被稱為“override”。我經(jīng)常混淆“overload”和“override”這兩個單詞。但是隨著各類C++的書越來越多,后來的程序員也許不會再犯我犯過的錯誤了。但是我打算澄清一下:

override是指派生類重寫基類的虛函數(shù),就象我們前面B類中重寫了A類中的foo()函數(shù)。重寫的函數(shù)必須有一致的參數(shù)表和返回值(C++標(biāo)準(zhǔn)答應(yīng)返回值不同的情況,這個我會在“語法”部分簡單介紹,但是很少編譯器支持這個feature)。這個單詞好象一直沒有什么合適的中文詞匯來對應(yīng),有人譯為“覆蓋”,還貼切一些。

overload約定成俗的被翻譯為“重載”。是指編寫一個與已有函數(shù)同名但是參數(shù)表不同的函數(shù)。例如一個函數(shù)即可以接受整型數(shù)作為參數(shù),也可以接受浮點(diǎn)數(shù)作為參數(shù)。 QQread.com 推出游戲功略 http://www.qqread.com/netgame/game/index.Html 魔獸世界 跑跑卡丁車 街頭籃球 水滸Q傳 龍與地下城OL 征服  軒轅劍5 FIFA07 熱血江湖 大唐風(fēng)云 夢幻西游 武林外傳 一.簡介


虛函數(shù)是C++中用于實(shí)現(xiàn)多態(tài)(polymorphism)的機(jī)制。核心理念就是通過基類訪問派生類定義的函數(shù)。假設(shè)我們有下面的類層次:

class A

{

public:

virtual void foo() { cout << "A::foo() is called" << endl;}

};

class B: public A

{

public:

virtual void foo() { cout << "B::foo() is called" << endl;}

};

那么,在使用的時候,我們可以:

A * a = new B();

a->foo(); // 在這里,a雖然是指向A的指針,但是被調(diào)用的函數(shù)(foo)卻是B的!

這個例子是虛函數(shù)的一個典型應(yīng)用,通過這個例子,也許你就對虛函數(shù)有了一些概念。它虛就虛在所謂“推遲聯(lián)編”或者“動態(tài)聯(lián)編”上,一個類函數(shù)的調(diào)用并不是在編譯時刻被確定的,而是在運(yùn)行時刻被確定的。由于編寫代碼的時候并不能確定被調(diào)用的是基類的函數(shù)還是哪個派生類的函數(shù),所以被成為“虛”函數(shù)。虛函數(shù)只能借助于指針或者引用來達(dá)到多態(tài)的效果,假如是下面這樣的代碼,則雖然是虛函數(shù),但它不是多態(tài)的:

class A

{

public:

virtual void foo();

};

class B: public A

{

virtual void foo();

};

void bar()

{

A a;

a.foo(); // A::foo()被調(diào)用

}

1.1 多態(tài) 在了解了虛函數(shù)的意思之后,再考慮什么是多態(tài)就很輕易了。仍然針對上面的類層次,但是使用的方法變的復(fù)雜了一些:

void bar(A * a)

{

a->foo(); // 被調(diào)用的是A::foo() 還是B::foo()?

}

因?yàn)閒oo()是個虛函數(shù),所以在bar這個函數(shù)中,只根據(jù)這段代碼,無從確定這里被調(diào)用的是A::foo()還是B::foo(),但是可以肯定的說:假如a指向的是A類的實(shí)例,則A::foo()被調(diào)用,假如a指向的是B類的實(shí)例,則B::foo()被調(diào)用。

這種同一代碼可以產(chǎn)生不同效果的特點(diǎn),被稱為“多態(tài)”。

1.2 多態(tài)有什么用?多態(tài)這么神奇,但是能用來做什么呢?這個命題我難以用一兩句話概括,一般的C++教程(或者其它面向?qū)ο笳Z言的教程)都用一個畫圖的例子來展示多態(tài)的用途,我就不再重復(fù)這個例子了,假如你不知道這個例子,隨便找本書應(yīng)該都有介紹。我試圖從一個抽象的角度描述一下,回頭再結(jié)合那個畫圖的例子,也許你就更輕易理解。

在面向?qū)ο蟮木幊讨校紫葧槍?shù)據(jù)進(jìn)行抽象(確定基類)和繼續(xù)(確定派生類),構(gòu)成類層次。這個類層次的使用者在使用它們的時候,假如仍然在需要基類的時候?qū)戓槍惖拇a,在需要派生類的時候?qū)戓槍ε缮惖拇a,就等于類層次完全暴露在使用者面前。假如這個類層次有任何的改變(增加了新類),都需要使用者“知道”(針對新類寫代碼)。這樣就增加了類層次與其使用者之間的耦合,有人把這種情況列為程序中的“bad smell”之一。

多態(tài)可以使程序員脫離這種窘境。再回頭看看1.1中的例子,bar()作為A-B這個類層次的使用者,它并不知道這個類層次中有多少個類,每個類都叫什么,但是一樣可以很好的工作,當(dāng)有一個C類從A類派生出來后,bar()也不需要“知道”(修改)。這完全歸功于多態(tài)--編譯器針對虛函數(shù)產(chǎn)生了可以在運(yùn)行時刻確定被調(diào)用函數(shù)的代碼。

1.3 如何“動態(tài)聯(lián)編” 編譯器是如何針對虛函數(shù)產(chǎn)生可以再運(yùn)行時刻確定被調(diào)用函數(shù)的代碼呢?也就是說,虛函數(shù)實(shí)際上是如何被編譯器處理的呢?Lippman在深度探索C++對象模型[1]中的不同章節(jié)講到了幾種方式,這里把“標(biāo)準(zhǔn)的”方式簡單介紹一下。

我所說的“標(biāo)準(zhǔn)”方式,也就是所謂的“VTABLE”機(jī)制。編譯器發(fā)現(xiàn)一個類中有被聲明為virtual的函數(shù),就會為其搞一個虛函數(shù)表,也就是VTABLE。VTABLE實(shí)際上是一個函數(shù)指針的數(shù)組,每個虛函數(shù)占用這個數(shù)組的一個slot。一個類只有一個VTABLE,不管它有多少個實(shí)例。派生類有自己的VTABLE,但是派生類的VTABLE與基類的VTABLE有相同的函數(shù)排列順序,同名的虛函數(shù)被放在兩個數(shù)組的相同位置上。在創(chuàng)建類實(shí)例的時候,編譯器還會在每個實(shí)例的內(nèi)存布局中增加一個vptr字段,該字段指向本類的VTABLE。通過這些手段,編譯器在看到一個虛函數(shù)調(diào)用的時候,就會將這個調(diào)用改寫,針對1.1中的例子:

void bar(A * a)

{

a->foo();

}

會被改寫為:

void bar(A * a)

{

(a->vptr[1])();

}

因?yàn)榕缮惡突惖膄oo()函數(shù)具有相同的VTABLE索引,而他們的vptr又指向不同的VTABLE,因此通過這樣的方法可以在運(yùn)行時刻決定調(diào)用哪個foo()函數(shù)。

雖然實(shí)際情況遠(yuǎn)非這么簡單,但是基本原理大致如此。

1.4 overload和override 虛函數(shù)總是在派生類中被改寫,這種改寫被稱為“override”。我經(jīng)常混淆“overload”和“override”這兩個單詞。但是隨著各類C++的書越來越多,后來的程序員也許不會再犯我犯過的錯誤了。但是我打算澄清一下:

override是指派生類重寫基類的虛函數(shù),就象我們前面B類中重寫了A類中的foo()函數(shù)。重寫的函數(shù)必須有一致的參數(shù)表和返回值(C++標(biāo)準(zhǔn)答應(yīng)返回值不同的情況,這個我會在“語法”部分簡單介紹,但是很少編譯器支持這個feature)。這個單詞好象一直沒有什么合適的中文詞匯來對應(yīng),有人譯為“覆蓋”,還貼切一些。

overload約定成俗的被翻譯為“重載”。是指編寫一個與已有函數(shù)同名但是參數(shù)表不同的函數(shù)。例如一個函數(shù)即可以接受整型數(shù)作為參數(shù),也可以接受浮點(diǎn)數(shù)作為參數(shù)。 QQread.com 推出游戲功略 http://www.qqread.com/netgame/game/index.html 魔獸世界 跑跑卡丁車 街頭籃球 水滸Q傳 龍與地下城OL 征服  軒轅劍5 FIFA07 熱血江湖 大唐風(fēng)云 夢幻西游 武林外傳 一.簡介


虛函數(shù)是C++中用于實(shí)現(xiàn)多態(tài)(polymorphism)的機(jī)制。核心理念就是通過基類訪問派生類定義的函數(shù)。假設(shè)我們有下面的類層次:

class A

{

public:

virtual void foo() { cout << "A::foo() is called" << endl;}

};

class B: public A

{

public:

virtual void foo() { cout << "B::foo() is called" << endl;}

};

那么,在使用的時候,我們可以:

A * a = new B();

a->foo(); // 在這里,a雖然是指向A的指針,但是被調(diào)用的函數(shù)(foo)卻是B的!

這個例子是虛函數(shù)的一個典型應(yīng)用,通過這個例子,也許你就對虛函數(shù)有了一些概念。它虛就虛在所謂“推遲聯(lián)編”或者“動態(tài)聯(lián)編”上,一個類函數(shù)的調(diào)用并不是在編譯時刻被確定的,而是在運(yùn)行時刻被確定的。由于編寫代碼的時候并不能確定被調(diào)用的是基類的函數(shù)還是哪個派生類的函數(shù),所以被成為“虛”函數(shù)。虛函數(shù)只能借助于指針或者引用來達(dá)到多態(tài)的效果,假如是下面這樣的代碼,則雖然是虛函數(shù),但它不是多態(tài)的:

class A

{

public:

virtual void foo();

};

class B: public A

{

virtual void foo();

};

void bar()

{

A a;

a.foo(); // A::foo()被調(diào)用

}

1.1 多態(tài) 在了解了虛函數(shù)的意思之后,再考慮什么是多態(tài)就很輕易了。仍然針對上面的類層次,但是使用的方法變的復(fù)雜了一些:

void bar(A * a)

{

a->foo(); // 被調(diào)用的是A::foo() 還是B::foo()?

}

因?yàn)閒oo()是個虛函數(shù),所以在bar這個函數(shù)中,只根據(jù)這段代碼,無從確定這里被調(diào)用的是A::foo()還是B::foo(),但是可以肯定的說:假如a指向的是A類的實(shí)例,則A::foo()被調(diào)用,假如a指向的是B類的實(shí)例,則B::foo()被調(diào)用。

這種同一代碼可以產(chǎn)生不同效果的特點(diǎn),被稱為“多態(tài)”。

1.2 多態(tài)有什么用?多態(tài)這么神奇,但是能用來做什么呢?這個命題我難以用一兩句話概括,一般的C++教程(或者其它面向?qū)ο笳Z言的教程)都用一個畫圖的例子來展示多態(tài)的用途,我就不再重復(fù)這個例子了,假如你不知道這個例子,隨便找本書應(yīng)該都有介紹。我試圖從一個抽象的角度描述一下,回頭再結(jié)合那個畫圖的例子,也許你就更輕易理解。

在面向?qū)ο蟮木幊讨校紫葧槍?shù)據(jù)進(jìn)行抽象(確定基類)和繼續(xù)(確定派生類),構(gòu)成類層次。這個類層次的使用者在使用它們的時候,假如仍然在需要基類的時候?qū)戓槍惖拇a,在需要派生類的時候?qū)戓槍ε缮惖拇a,就等于類層次完全暴露在使用者面前。假如這個類層次有任何的改變(增加了新類),都需要使用者“知道”(針對新類寫代碼)。這樣就增加了類層次與其使用者之間的耦合,有人把這種情況列為程序中的“bad smell”之一。

多態(tài)可以使程序員脫離這種窘境。再回頭看看1.1中的例子,bar()作為A-B這個類層次的使用者,它并不知道這個類層次中有多少個類,每個類都叫什么,但是一樣可以很好的工作,當(dāng)有一個C類從A類派生出來后,bar()也不需要“知道”(修改)。這完全歸功于多態(tài)--編譯器針對虛函數(shù)產(chǎn)生了可以在運(yùn)行時刻確定被調(diào)用函數(shù)的代碼。

1.3 如何“動態(tài)聯(lián)編” 編譯器是如何針對虛函數(shù)產(chǎn)生可以再運(yùn)行時刻確定被調(diào)用函數(shù)的代碼呢?也就是說,虛函數(shù)實(shí)際上是如何被編譯器處理的呢?Lippman在深度探索C++對象模型[1]中的不同章節(jié)講到了幾種方式,這里把“標(biāo)準(zhǔn)的”方式簡單介紹一下。

我所說的“標(biāo)準(zhǔn)”方式,也就是所謂的“VTABLE”機(jī)制。編譯器發(fā)現(xiàn)一個類中有被聲明為virtual的函數(shù),就會為其搞一個虛函數(shù)表,也就是VTABLE。VTABLE實(shí)際上是一個函數(shù)指針的數(shù)組,每個虛函數(shù)占用這個數(shù)組的一個slot。一個類只有一個VTABLE,不管它有多少個實(shí)例。派生類有自己的VTABLE,但是派生類的VTABLE與基類的VTABLE有相同的函數(shù)排列順序,同名的虛函數(shù)被放在兩個數(shù)組的相同位置上。在創(chuàng)建類實(shí)例的時候,編譯器還會在每個實(shí)例的內(nèi)存布局中增加一個vptr字段,該字段指向本類的VTABLE。通過這些手段,編譯器在看到一個虛函數(shù)調(diào)用的時候,就會將這個調(diào)用改寫,針對1.1中的例子:

void bar(A * a)

{

a->foo();

}

會被改寫為:

void bar(A * a)

{

(a->vptr[1])();

}

因?yàn)榕缮惡突惖膄oo()函數(shù)具有相同的VTABLE索引,而他們的vptr又指向不同的VTABLE,因此通過這樣的方法可以在運(yùn)行時刻決定調(diào)用哪個foo()函數(shù)。

雖然實(shí)際情況遠(yuǎn)非這么簡單,但是基本原理大致如此。

1.4 overload和override 虛函數(shù)總是在派生類中被改寫,這種改寫被稱為“override”。我經(jīng)常混淆“overload”和“override”這兩個單詞。但是隨著各類C++的書越來越多,后來的程序員也許不會再犯我犯過的錯誤了。但是我打算澄清一下:

override是指派生類重寫基類的虛函數(shù),就象我們前面B類中重寫了A類中的foo()函數(shù)。重寫的函數(shù)必須有一致的參數(shù)表和返回值(C++標(biāo)準(zhǔn)答應(yīng)返回值不同的情況,這個我會在“語法”部分簡單介紹,但是很少編譯器支持這個feature)。這個單詞好象一直沒有什么合適的中文詞匯來對應(yīng),有人譯為“覆蓋”,還貼切一些。

overload約定成俗的被翻譯為“重載”。是指編寫一個與已有函數(shù)同名但是參數(shù)表不同的函數(shù)。例如一個函數(shù)即可以接受整型數(shù)作為參數(shù),也可以接受浮點(diǎn)數(shù)作為參數(shù)。 QQread.com 推出游戲功略 http://www.qqread.com/netgame/game/index.html 魔獸世界 跑跑卡丁車 街頭籃球 水滸Q傳 龍與地下城OL 征服  軒轅劍5 FIFA07 熱血江湖 大唐風(fēng)云 夢幻西游 武林外傳 right">(出處:清風(fēng)軟件下載學(xué)院)

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 绥宁县| 平江县| 香格里拉县| 比如县| 陆丰市| 万山特区| 玉山县| 宁远县| 贡山| 新源县| 黔南| 福贡县| 阿克| 兰州市| 建德市| 玉溪市| 清水河县| 昆山市| 渭南市| 平谷区| 四平市| 高密市| 枣阳市| 信阳市| 嘉鱼县| 菏泽市| 奉化市| 武胜县| 鲁山县| 富蕴县| 尚志市| 资阳市| 鹤岗市| 万山特区| 鄂托克前旗| 上栗县| 眉山市| 黎平县| 江口县| 横山县| 新晃|