最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++ 基礎(chǔ)教程之虛函數(shù)實(shí)例代碼詳解

 更新時(shí)間:2020年02月22日 20:14:11   作者:王的博客  
虛函數(shù)在 c++ 的繼承體系中是一個(gè)非常重要概念,讓我們可以在子類中復(fù)寫父類的方法。這篇文章主要介紹了C++ 基礎(chǔ)教程之虛函數(shù)實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下

虛函數(shù)的定義

虛函數(shù):就是在基類的成員函數(shù)前加關(guān)鍵字virtual(即被virtual關(guān)鍵字修飾的成員函數(shù)),并在一個(gè)或多個(gè)派生類中被重新定義的成員函數(shù);虛函數(shù):就是在編譯的時(shí)候不確定要調(diào)用哪個(gè)函數(shù),而是動態(tài)決定將要調(diào)用哪個(gè)函數(shù)。它的作用就是為了能讓這個(gè)函數(shù)在它的子類里面可以被重載,這樣的話,編譯器就可以使用后期綁定來達(dá)到多態(tài)了,也就是用基類的指針來調(diào)用子類的這個(gè)函數(shù);虛函數(shù)的作用:在于用專業(yè)術(shù)語來解釋就是實(shí)現(xiàn)多態(tài)性,多態(tài)性是將接口與實(shí)現(xiàn)進(jìn)行分離,通過指向派生類的基類指針或引用,訪問派生類中同名覆蓋成員函數(shù);用形象的語言來解釋就是實(shí)現(xiàn)以共同的方法,但因個(gè)體差異,而采用不同的策略;虛函數(shù)用法格式為:virtual 函數(shù)返回類型 函數(shù)名(參數(shù)表) {函數(shù)體};

虛函數(shù)在 c++ 的繼承體系中是一個(gè)非常重要概念,讓我們可以在子類中復(fù)寫父類的方法。學(xué)到這里我還不知道在 c++ 中是否有抽象類的概念,那么學(xué)習(xí)過虛函數(shù)我們就知道通過(純)虛函數(shù)可以實(shí)現(xiàn) java 中的抽象類,

要實(shí)現(xiàn)虛函數(shù)需要兩個(gè)步驟進(jìn)行修改

  • 在父類中,在函數(shù)GetName()前面加上virtual
  • 在子類中,在函數(shù)GetName()后面加上override

再次運(yùn)行編譯運(yùn)行程序就得到我們想要結(jié)果了

Shap rectangle

下面開始正文

virtual 函數(shù)

示例代碼如下:

#include <stdio.h>
class base {
public:
 virtual void name(){printf("base\n");};
 virtual ~base(){};
};
class plus: public base {
public:
 virtual void name(){printf("plus\n");};
};
void fv(base b){
 b.name();
}
void fp(base &b){
 b.name();
}
int main(){
 base b;
 plus p;
 fv(b);
 fv(p);
 fp(b);
 fp(p);
 return 0;
}

程序輸出:

base base base plus

這里涉及到一個(gè)c++知識點(diǎn)-- 向上強(qiáng)制轉(zhuǎn)換 :將派生類引用或指針轉(zhuǎn)換為基類引用或指針。該規(guī)則使得公有繼承不需要進(jìn)行顯示類型轉(zhuǎn)化,它是is-a 規(guī)則的一部分。

相反的過程被稱為-- 向下強(qiáng)制轉(zhuǎn)換 ,向下強(qiáng)制類型轉(zhuǎn)換必須是顯示的。因?yàn)榕缮惪赡軐愡M(jìn)行拓展,新增的成員變量和函數(shù)不能應(yīng)用于基類。

隱式向上強(qiáng)制轉(zhuǎn)換使得基類指針或引用可以指向基類對象或派生類對象,因此需要 動態(tài)聯(lián)編 。C++ 使用虛成員函數(shù)函數(shù)滿足這種需求。

動態(tài)聯(lián)編

編譯器在編譯時(shí)要將調(diào)用的函數(shù)對應(yīng)相應(yīng)的可執(zhí)行代碼,此過程為 函數(shù)聯(lián)編(binding) ,在C++因?yàn)楹瘮?shù)重載的原因,需要查看調(diào)用函數(shù)名和傳入?yún)?shù)才能確認(rèn)是哪一個(gè)函數(shù)。在編譯的時(shí)候可以確認(rèn)使用哪一個(gè)函數(shù)的聯(lián)編被稱為 靜態(tài)聯(lián)編 或 早期聯(lián)編 。

同時(shí)因?yàn)関irtual函數(shù)的存在,編譯工作變得更加復(fù)雜,如示例函數(shù)所示,具體使用的哪個(gè)類型對象不能確認(rèn)。為此編譯器必須生成一些代碼,使得在程序運(yùn)行的時(shí)候選擇正確的虛函數(shù),這被稱為 動態(tài)聯(lián)編 ,又被稱為 晚期聯(lián)編 。

為了驗(yàn)證上面所述我們可以做一組對照,首先我們用 gnu 工具 nm 來查看 sysbols,可以發(fā)現(xiàn)如下的部分:

$ nm virtual.exe | grep -c -E "plus|base"

然后我們改造一下上面的代碼:

class base {
public:
 void name(){printf("base\n");}; // 修改
 virtual ~base(){};
};
class plus: public base {
public:
 void name(){printf("plus\n");}; // 修改
};

編譯后重新執(zhí)行 nm 命令:

nm virtual_.exe | grep -c -E "plus|base" 45

經(jīng)過比對后我們會發(fā)現(xiàn)修改后缺少了以下symbols:

000000000040509c p .pdata$_ZN4plus4nameEv 0000000000402e00 t .text$_ZN4plus4nameEv 00000000004060a0 r .xdata$_ZN4plus4nameEv 0000000000402e00 T _ZN4plus4nameEv

動態(tài)聯(lián)編在效率上要低于靜態(tài)聯(lián)編,在C++ 中默認(rèn)使用靜態(tài)聯(lián)編。C++ 之父strousstup 認(rèn)為 C++ 指導(dǎo)原則之一是不要為不使用的特性付出代價(jià)(cpu、memory等)。

所以在派生類不需要去重寫基類函數(shù)時(shí),則不要將其聲明為virtual函數(shù)。

virtual 函數(shù)工作原理

虛函數(shù)表示每一個(gè)使用C++的開發(fā)者耳熟能詳?shù)臇|西,有一個(gè)道經(jīng)典的試題如下:

#include <stdio.h>
class base
{
public:
 base(){};
 virtual ~base() { printf("base\n"); };
};
class plus : public base
{
public:
 plus(/* args */){};
 virtual ~plus() { printf("plus\n"); };
};
class plus2 : public base
{
public:
 plus2(/* args */){};
 ~plus2() { printf("plus2\n"); };
};
class plus3 : public base
{
public:
 virtual void name() { printf("plus3"); };
 plus3(/* args */){};
 virtual ~plus3() { printf("plus3\n"); };
};
class empty
{
private:
 /* data */
public:
 empty(/* args */){};
 ~empty() { printf("empty\n"); };
};
int main()
{
 base b;
 printf("base: %d\n", sizeof(b));
 plus p;
 printf("plus: %d\n", sizeof(p));
 plus2 p2;
 printf("plus2: %d\n", sizeof(p2));
 plus3 p3;
 printf("plus3: %d\n", sizeof(p3));
 empty e;
 printf("empty: %d\n", sizeof(e));
}

其最終輸出的結(jié)果如下:

base: 8 plus: 8 plus2: 8 plus3: 8 empty: 1 empty plus3 base plus2 base plus base base

ps: 由于操作系統(tǒng)位數(shù)的影響結(jié)果可能有變動,在x64位系統(tǒng)中指針內(nèi)存分配大小為 8 字節(jié),x86 系統(tǒng)中指針內(nèi)存分配大小為 4。

我們可以清楚的看到,只要存在虛函數(shù)不論是成員函數(shù)異或是析構(gòu)函數(shù),是在類中定義或繼承都會有包含一個(gè)虛函數(shù)表。而這里的8字節(jié)就是分配給了虛函數(shù)表的指針。

我們可以通過gnu tool gdb 指令進(jìn)行驗(yàn)證,在觸發(fā)斷點(diǎn)之后通過 info local 命令去查看:

(gdb) info locals
b = {_vptr.base = 0x555555755d20 <vtable for base+16>}
p = {<base> = {_vptr.base = 0x555555755d00 <vtable for plus+16>}, <No data fields>}
p2 = {<base> = {_vptr.base = 0x555555755ce0 <vtable for plus2+16>}, <No data fields>}
p3 = {<base> = {_vptr.base = 0x555555755cb8 <vtable for plus3+16>}, <No data fields>}
e = {<No data fields>}

我們可以看到每一個(gè)對象內(nèi)都有一個(gè)指針指向vtable。

當(dāng)一個(gè)基類聲明一個(gè)虛函數(shù)后,在創(chuàng)建對象的時(shí)候會將該函數(shù)地址加入虛函數(shù)列表中,如果派生類重寫了該函數(shù),則會用新函數(shù)地址替換,如果其定義了新函數(shù),則會將新函數(shù)的指針加入虛表中。

示例代碼如下:

#include <stdio.h>
class base
{
public:
 base(){};
 virtual const char* feature(){return "test";};
 virtual void name() {printf("base\n");}
 virtual ~base() { printf("~base\n"); };
};
class plus : public base
{
public:
 plus(/* args */){};
 virtual void name() {printf("plus\n");}
 virtual void parant() {printf("base\n");}
 ~plus() { printf("plus\n"); };
};
int main()
{
 base b;
 printf("base: %ld\n", size_t(&b));
 plus p;
 printf("plus: %ld\n", size_t(&p));
}

仍然用 gdb 來驗(yàn)證,斷點(diǎn)后通過 info vtbl 命令查看:

(gdb) info vtbl p
vtable for 'plus' @ 0x555555755d08 (subobject @ 0x7fffffffe010):
[0]: 0x555555554b4a <base::feature()>
[1]: 0x555555554bf8 <plus::name()>
[2]: 0x555555554c30 <plus::~plus()>
[3]: 0x555555554c66 <plus::~plus()>
[4]: 0x555555554c14 <plus::parant()>
(gdb) info vtbl b
vtable for 'base' @ 0x555555755d40 (subobject @ 0x7fffffffe008):
[0]: 0x555555554b4a <base::feature()>
[1]: 0x555555554b5c <base::name()>

當(dāng)調(diào)用虛函數(shù)的時(shí)候,會在虛函數(shù)表中尋找對應(yīng)的函數(shù)地址,因此它每一次調(diào)用動會多做一步匹配,相比靜態(tài)聯(lián)編的非虛函數(shù)要更加耗時(shí)。

需要注意的是構(gòu)造函數(shù)不能聲明為虛函數(shù),而如果一個(gè)類作為除非不作為基類,否則建議聲明一個(gè)虛析構(gòu)函數(shù)。

總結(jié)

到此這篇關(guān)于C++ 基礎(chǔ)教程之虛函數(shù)實(shí)例代碼詳解的文章就介紹到這了,更多相關(guān)c++ 虛函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 數(shù)據(jù)結(jié)構(gòu)之?dāng)?shù)組Array實(shí)例詳解

    數(shù)據(jù)結(jié)構(gòu)之?dāng)?shù)組Array實(shí)例詳解

    這篇文章主要介紹了數(shù)據(jù)結(jié)構(gòu)之?dāng)?shù)組Array實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • C++程序中啟動線程的方法

    C++程序中啟動線程的方法

    這篇文章主要介紹了C++程序中啟動線程的方法,作者針對C++11版本中的一些新特性進(jìn)行了解說,需要的朋友可以參考下
    2015-07-07
  • C語言統(tǒng)計(jì)輸入字符各個(gè)字母出現(xiàn)頻率的解題思路

    C語言統(tǒng)計(jì)輸入字符各個(gè)字母出現(xiàn)頻率的解題思路

    這篇文章主要介紹了C語言統(tǒng)計(jì)輸入字符各個(gè)字母出現(xiàn)頻率的解題思路,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2015-08-08
  • C++實(shí)現(xiàn)銀行排隊(duì)系統(tǒng)

    C++實(shí)現(xiàn)銀行排隊(duì)系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)銀行排隊(duì)系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • C++鏈表實(shí)現(xiàn)通訊錄管理系統(tǒng)

    C++鏈表實(shí)現(xiàn)通訊錄管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C++鏈表實(shí)現(xiàn)通訊錄管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • C/C++: Inline function, calloc 對比 malloc

    C/C++: Inline function, calloc 對比 malloc

    以下是對c/c++中的malloc函數(shù)與calloc函數(shù)的區(qū)別以及它們之間的聯(lián)系進(jìn)行了介紹,需要的朋友可以過來參考下
    2016-07-07
  • C/C++堆區(qū)專篇精講

    C/C++堆區(qū)專篇精講

    一直以來總是對這個(gè)問題的認(rèn)識比較朦朧,我相信很多朋友也是這樣的,總是聽到內(nèi)存一會在棧上分配,一會又在堆上分配,那么它們之間到底是怎么的區(qū)別呢,讓我們一起來看看
    2022-10-10
  • C++?typedef常見用法詳解

    C++?typedef常見用法詳解

    這篇文章主要介紹了C++?typedef用法詳解,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03
  • C語言中結(jié)構(gòu)體封裝全局變量用法說明

    C語言中結(jié)構(gòu)體封裝全局變量用法說明

    這篇文章主要介紹了C語言中結(jié)構(gòu)體封裝全局變量用法說明,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • 基于Qt實(shí)現(xiàn)簡單的計(jì)算器

    基于Qt實(shí)現(xiàn)簡單的計(jì)算器

    這篇文章主要介紹了如何使用Qt框架實(shí)現(xiàn)一個(gè)簡單的計(jì)算器應(yīng)用,我們將使用C++編程語言和Qt的圖形用戶界面庫來開發(fā)這個(gè)應(yīng)用,并展示如何實(shí)現(xiàn)基本的算術(shù)操作,希望對大家有所幫助
    2023-11-11

最新評論

尚义县| 永安市| 晋宁县| 西乡县| 新巴尔虎右旗| 灌云县| 绥江县| 诸城市| 蕉岭县| 霍州市| 济南市| 临泉县| 十堰市| 韶关市| 凤城市| 乃东县| 富蕴县| 静安区| 顺平县| 拜城县| 开远市| 黄浦区| 小金县| 化德县| 广元市| 随州市| 马鞍山市| 三都| 靖远县| 锡林浩特市| 临沭县| 洛宁县| 绍兴县| 莒南县| 格尔木市| 徐闻县| 辽宁省| 聊城市| 宜川县| 太保市| 郧西县|