C++中的多態(tài)與虛函數(shù)的內(nèi)部實(shí)現(xiàn)方法
1、什么是多態(tài)
多態(tài)性可以簡(jiǎn)單概括為“一個(gè)接口,多種行為”。
也就是說(shuō),向不同的對(duì)象發(fā)送同一個(gè)消息, 不同的對(duì)象在接收時(shí)會(huì)產(chǎn)生不同的行為(即方法)。也就是說(shuō),每個(gè)對(duì)象可以用自己的方式去響應(yīng)共同的消息。所謂消息,就是調(diào)用函數(shù),不同的行為就是指不同的實(shí)現(xiàn),即執(zhí)行不同的函數(shù)。這是一種泛型技術(shù),即用相同的代碼實(shí)現(xiàn)不同的動(dòng)作。這體現(xiàn)了面向?qū)ο缶幊痰膬?yōu)越性。
多態(tài)分為兩種:
(1)編譯時(shí)多態(tài):主要通過(guò)函數(shù)的重載和模板來(lái)實(shí)現(xiàn)。
(2)運(yùn)行時(shí)多態(tài):主要通過(guò)虛函數(shù)來(lái)實(shí)現(xiàn)。
2、幾個(gè)相關(guān)概念
(1)覆蓋、重寫(override)
override指基類的某個(gè)成員函數(shù)為虛函數(shù),派生類又定義一成員函數(shù),除函數(shù)體的其余部分都與基類的成員函數(shù)相同。注意,如果只是函數(shù)名相同,形參或返回類型不同的話,就不能稱為override,而是hide。
(2)重載(overload)
指同一個(gè)作用域出生多個(gè)函數(shù)名相同,但是形參不同的函數(shù)。編譯器在編譯的時(shí)候,通過(guò)實(shí)參的個(gè)數(shù)和類型,選擇最終調(diào)用的函數(shù)。
(3)隱藏(hide)
分為兩種:
1)局部變量或者函數(shù)隱藏了全局變量或者函數(shù)
2)派生類擁有和基類同名的成員函數(shù)或成員變量。
產(chǎn)生的結(jié)果:使全局或基類的變量、函數(shù)不可見(jiàn)。
3、幾個(gè)簡(jiǎn)單的例子
/****************************************************************************************************** * File:PolymorphismTest * Introduction:測(cè)試多態(tài)的一些特性。 * Author:CoderCong * Date:20141114 * LastModifiedDate:20160113 *******************************************************************************************************/ #include "stdafx.h" #include <iostream> using namespace std; class A { public: void foo() { printf("1\n"); } virtual void fun() { printf("2\n"); } }; class B : public A { public: void foo() //由于基類的foo函數(shù)并不是虛函數(shù),所以是隱藏,而不是重寫 { printf("3\n"); } void fun() //重寫 { printf("4\n"); } }; int main(void) { A a; B b; A *p = &a; p->foo(); //輸出1。 p->fun(); //輸出2。 p = &b; p->foo(); //輸出1。因?yàn)閜是基類指針,p->foo指向一個(gè)具有固定偏移量的函數(shù)。也就是基類函數(shù) p->fun(); //輸出4。多態(tài)。雖然p是基類指針,但實(shí)際上指向的是一個(gè)子類對(duì)象。p->fun指向的是一個(gè)虛函數(shù)。按照動(dòng)態(tài)類型,調(diào)用子類函數(shù) return 0; }
4、運(yùn)行時(shí)多態(tài)以及虛函數(shù)的內(nèi)部實(shí)現(xiàn)
看了上邊幾個(gè)簡(jiǎn)單的例子,我恍然大悟,原來(lái)這就是多態(tài),這么簡(jiǎn)單,明白啦!
好,那我們?cè)倏匆粋€(gè)例子:
class A { public: virtual void FunA() { cout << "FunA1" << endl; }; virtual void FunAA() { cout << "FunA2" << endl; } }; class B { public: virtual void FunB() { cout << "FunB" << endl; } }; class C :public A, public B { public: virtual void FunA() { cout << "FunA1C" << endl; }; }; int _tmain(int argc, _TCHAR* argv[]) { C objC; A *pA = &objC; B *pB = &objC; C *pC = &objC; printf("%d %d\n", &objC, objC); printf("%d %d\n", pA, *pA); printf("%d %d\n", pB, *pB); printf("%d %d\n", pC, *pC); return 0; }
運(yùn)行結(jié)果:
5241376 1563032
5241376 1563032
5241380 1563256
5241376 1563032
細(xì)心的同志一定發(fā)現(xiàn)了pB出了問(wèn)題,為什么明明都是指向objC的指針,pB跟別人的值都不一樣呢?
是不是編譯器出了問(wèn)題呢?
當(dāng)然不是!我們先講結(jié)論:
(1)每一個(gè)含有虛函數(shù)的類,都會(huì)生成虛表(virtual table)。這個(gè)表,記錄了對(duì)象的動(dòng)態(tài)類型,決定了執(zhí)行此對(duì)象的虛成員函數(shù)的時(shí)候,真正執(zhí)行的那一個(gè)成員函數(shù)。
(2)對(duì)于有多個(gè)基類的類對(duì)象,會(huì)有多個(gè)虛表,每一個(gè)基類對(duì)應(yīng)一個(gè)虛表,同時(shí),虛表的順序和繼承時(shí)的順序相同。
(3)在每一個(gè)類對(duì)象所占用的內(nèi)存中,虛指針位于最前邊,每個(gè)虛指針指向?qū)?yīng)的虛表。
先從簡(jiǎn)單的單個(gè)基類說(shuō)起:
class A { public: virtual void FunA() { cout << "FunA1" << endl; } virtual void FunA2() { cout << "FunA2" << endl; } }; class C :public A { virtual void FunA() { cout << "FunA1C" << endl; } }; int _tmain(int argc, _TCHAR* argv[]) { A *pA = new A; C *pC = new C; typedef void (*Fun)(void); Fun fun= (Fun)*((int*)(*(int*)pA)); fun();//pA指向的第一個(gè)函數(shù) fun = (Fun)*((int*)(*(int*)pA) +1); fun();//pA指向的第二個(gè)函數(shù) fun = (Fun)*((int*)(*(int*)pC)); fun();//pC指向的第一個(gè)函數(shù) fun = (Fun)*((int*)(*(int*)pC) + 1); fun();//pC指向的第二個(gè)函數(shù) return 0; }
運(yùn)行結(jié)果:
FunA2
FunA1C
FunA2
int _tmain(int argc, _TCHAR* argv[]) { C objC; A *pA = &objA; B *pB = &objC; C *pC = &objC; typedef void (*Fun)(void); Fun fun = (Fun)*((int*)(*(int*)pC)); fun();//第一個(gè)表第一個(gè)函數(shù) fun = (Fun)*((int*)(*(int*)pC)+1); fun();//第一個(gè)表第二個(gè)函數(shù) fun = (Fun)*((int*)(*((int*)pC+1))); fun();<span style="white-space:pre"> </span>//第二個(gè)表第一個(gè)函數(shù) fun = (Fun)*((int*)(*(int*)pB)); fun();//pB指向的表的第一個(gè)函數(shù) return 0; }
哈哈,和我們的猜測(cè)完全一致:
FunA2
FunB
FunB
以上就是小編為大家?guī)?lái)的C++中的多態(tài)與虛函數(shù)的內(nèi)部實(shí)現(xiàn)方法全部?jī)?nèi)容了,希望大家多多支持我們~
欄 目:C語(yǔ)言
下一篇:C++ 簡(jiǎn)單的任務(wù)隊(duì)列詳解
本文標(biāo)題:C++中的多態(tài)與虛函數(shù)的內(nèi)部實(shí)現(xiàn)方法
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/1926.html
您可能感興趣的文章
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 01-10深入理解C++中常見(jiàn)的關(guān)鍵字含義
- 01-10使用C++實(shí)現(xiàn)全排列算法的方法詳解
- 01-10深入Main函數(shù)中的參數(shù)argc,argv的使用詳解
- 01-10c++中inline的用法分析
- 01-10如何尋找數(shù)組中的第二大數(shù)
- 01-10用C++實(shí)現(xiàn)DBSCAN聚類算法
- 01-10全排列算法的非遞歸實(shí)現(xiàn)與遞歸實(shí)現(xiàn)的方法(C++)
- 01-10C++大數(shù)模板(推薦)
- 01-10淺談C/C++中的static與extern關(guān)鍵字的使用詳解


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫分段 用c語(yǔ)言表示分段
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)
- 04-02c語(yǔ)言編寫函數(shù)冒泡排序 c語(yǔ)言冒泡排
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求
隨機(jī)閱讀
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 04-02jquery與jsp,用jquery
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載
- 01-10C#中split用法實(shí)例總結(jié)
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-10delphi制作wav文件的方法