深入解析C++中的虛函數(shù)與多態(tài)
1.C++中的虛函數(shù)
C++中的虛函數(shù)的作用主要是實(shí)現(xiàn)了多態(tài)的機(jī)制。關(guān)于多態(tài),簡而言之就是用父類型別的指針指向其子類的實(shí)例,然后通過父類的指針調(diào)用實(shí)際子類的成員函數(shù)。這種技術(shù)可以讓父類的指針有“多種形態(tài)”,這是一種泛型技術(shù)。所謂泛型技術(shù),說白了就是試圖使用不變的代碼來實(shí)現(xiàn)可變的算法。比如:模板技術(shù),RTTI技術(shù),虛函數(shù)技術(shù),要么是試圖做到在編譯時(shí)決議,要么試圖做到運(yùn)行時(shí)決議。
對(duì)C++ 了解的人都應(yīng)該知道虛函數(shù)(Virtual Function)是通過一張?zhí)摵瘮?shù)表(Virtual Table)和一個(gè)指向虛函數(shù)表的指針(vptr)來實(shí)現(xiàn)的。虛函數(shù)表,簡稱為vtbl,虛函數(shù)表表對(duì)實(shí)現(xiàn)多態(tài)起著至關(guān)重要的作用。在這個(gè)表中,主要保存了一個(gè)類中的虛函數(shù)的地址,這張表解決了繼承、覆蓋的問題,保證其內(nèi)容能真實(shí)反應(yīng)實(shí)際的函數(shù)。每一個(gè)包含虛函數(shù)的類的實(shí)例都包含一個(gè)cptr指針,指向虛函數(shù)表的首地址。我們可以通過這個(gè)指針找到要訪問的虛函數(shù)的,完成虛函數(shù)的調(diào)用主要包括:找到虛函數(shù)表的首地址(vptr),通過cptr找到要使用虛函數(shù)地址,調(diào)用虛函數(shù)。那么使用虛函數(shù)大家總要考慮效率的問題,實(shí)際上為了提高效率,C++的編譯器是保證虛函數(shù)表的指針存在于對(duì)象實(shí)例中最前面的位置,這是為了保證取到虛函數(shù)表的有最高的性能,這意味著我們通過對(duì)象實(shí)例的地址得到這張?zhí)摵瘮?shù)表,然后通過遍歷表就可以找到其中的虛函數(shù)的地址,然后調(diào)用相應(yīng)的函數(shù)。不妨看看下面的代碼:
#include <iostream>
using namespace std;
class Base
{
public:
virtual void f() { cout << "Base::f" << endl; }
virtual void g() { cout << "Base::g" << endl; }
virtual void h() { cout << "Base::h" << endl; }
};
typedef void(*Fun)(void);
int main()
{
Base b;
Fun pFun = NULL;
cout << "虛函數(shù)表地址:" << (int*)(&b) << endl;
cout << "虛函數(shù)表 — 第一個(gè)函數(shù)地址:" << (int*)*(int*)(&b) << endl;
pFun = (Fun)*((int*)*(int*)(&b));
pFun();
return 0;
}
通過這個(gè)示例,可以看到,通過強(qiáng)行把&b轉(zhuǎn)成int *,取得虛函數(shù)表的地址(vptr),然后,再次取址就可以得到第一個(gè)虛函數(shù)的地址了,也就是Base::f(),這在上面的程序中得到了驗(yàn)證(把int* 強(qiáng)制轉(zhuǎn)成了函數(shù)指針)。通過這個(gè)示例,我們就可以知道如果要調(diào)用Base::g()和Base::h(),其代碼如下:
(Fun)*((int*)*(int*)(&b)+0); // Base::f()
(Fun)*((int*)*(int*)(&b)+1); // Base::g()
(Fun)*((int*)*(int*)(&b)+2); // Base::h()
可以看看虛函數(shù)表的圖是怎么畫的:
大家都知道,多態(tài)是通過繼承實(shí)現(xiàn)的,那么我們要說說虛函數(shù)繼承的問題。繼承就涉及到了虛函數(shù)的覆蓋了,實(shí)際上不被覆蓋的虛函數(shù)和多態(tài)又有什么聯(lián)系呢?這里我們討論有覆蓋的虛函數(shù)表是什么樣的,假設(shè)存在下面的繼承關(guān)系:
看看虛函數(shù)表示什么樣的:
可以發(fā)現(xiàn),Base::f()被覆蓋了,這樣若把Derive的實(shí)例賦值給一個(gè)基類Base指針pBase,通過pBase->f();則訪問的是子類中的f()也就是完成了多態(tài)。那么虛函數(shù)表中的內(nèi)容到底是怎么樣的呢?可以看看下面的四句話就會(huì)明白!
1.虛函數(shù)按照其聲明順序放于表中。
2.父類的虛函數(shù)在子類的虛函數(shù)前面。
3.覆蓋的f()函數(shù)被放到了虛表中原來父類虛函數(shù)的位置。
4.沒有被覆蓋的函數(shù)依舊。
2.用虛函數(shù)實(shí)現(xiàn)多態(tài)
看看下面的多態(tài)的代碼:
#include <iostream>
using namespace std;
class Base
{
public:
virtual void Print()
{
cout<<"Base::Print()"<<endl;
}
};
class Derive : public Base
{
public:
virtual void Print()
{
cout<<"Derive::Print()"<<endl;
}
};
int main()
{
Derive derive;
Base *pBase = &derive;
pBase->Print();
return 0;
}
//多態(tài)代碼
實(shí)現(xiàn)虛函數(shù)的代碼,一定要切記:一定是基類的指針指向子類的對(duì)象的地址。首先試著理解一下用虛函數(shù)實(shí)現(xiàn)多態(tài)的原理,如果實(shí)在沒理解為什么虛函數(shù)能實(shí)現(xiàn)多態(tài),又為什么這樣實(shí)現(xiàn)多態(tài),上網(wǎng)再搜一搜相關(guān)的資料?。?!
上一篇:vector,map,list,queue的區(qū)別詳細(xì)解析
欄 目:C語言
下一篇:關(guān)于STL中l(wèi)ist容器的一些總結(jié)
本文標(biāo)題:深入解析C++中的虛函數(shù)與多態(tài)
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/4082.html
您可能感興趣的文章
- 04-02c語言沒有round函數(shù) round c語言
- 01-10深入理解約瑟夫環(huán)的數(shù)學(xué)優(yōu)化方法
- 01-10深入二叉樹兩個(gè)結(jié)點(diǎn)的最低共同父結(jié)點(diǎn)的詳解
- 01-10數(shù)據(jù)結(jié)構(gòu)課程設(shè)計(jì)- 解析最少換車次數(shù)的問題詳解
- 01-10深入理解C++中常見的關(guān)鍵字含義
- 01-10使用C++實(shí)現(xiàn)全排列算法的方法詳解
- 01-10深入Main函數(shù)中的參數(shù)argc,argv的使用詳解
- 01-10深入第K大數(shù)問題以及算法概要的詳解
- 01-10深入解析最長公共子串
- 01-10c++中inline的用法分析


閱讀排行
本欄相關(guān)
- 04-02c語言函數(shù)調(diào)用后清空內(nèi)存 c語言調(diào)用
- 04-02func函數(shù)+在C語言 func函數(shù)在c語言中
- 04-02c語言的正則匹配函數(shù) c語言正則表達(dá)
- 04-02c語言用函數(shù)寫分段 用c語言表示分段
- 04-02c語言中對(duì)數(shù)函數(shù)的表達(dá)式 c語言中對(duì)
- 04-02c語言編寫函數(shù)冒泡排序 c語言冒泡排
- 04-02c語言沒有round函數(shù) round c語言
- 04-02c語言分段函數(shù)怎么求 用c語言求分段
- 04-02C語言中怎么打出三角函數(shù) c語言中怎
- 04-02c語言調(diào)用函數(shù)求fibo C語言調(diào)用函數(shù)求
隨機(jī)閱讀
- 01-10使用C語言求解撲克牌的順子及n個(gè)骰子
- 08-05織夢dedecms什么時(shí)候用欄目交叉功能?
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-10C#中split用法實(shí)例總結(jié)
- 04-02jquery與jsp,用jquery
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-10delphi制作wav文件的方法
- 01-11ajax實(shí)現(xiàn)頁面的局部加載