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

C++的多態(tài)和虛函數(shù)你真的了解嗎

 更新時(shí)間:2022年02月14日 15:49:25   作者:山頂夕景  
這篇文章主要為大家詳細(xì)介紹了C++的多態(tài)和虛函數(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助

一、C++的面試??键c(diǎn)

阿里雖然是國(guó)內(nèi)Java的第一大廠但是并非所有的業(yè)務(wù)都是由Java支撐,很多服務(wù)和中下層的存儲(chǔ),計(jì)算,網(wǎng)絡(luò)服務(wù),大規(guī)模的分布式任務(wù)都是由C++編寫。在阿里所有部門當(dāng)中對(duì)C++考察最深的可能就是阿里云。

阿里對(duì)C++的??键c(diǎn):

1.STL 容器相關(guān)實(shí)現(xiàn)

2.C++新特性的了解

3.多態(tài)和虛函數(shù)的實(shí)現(xiàn)

4.指針的使用

二、阿里真題

2.1 真題一

現(xiàn)在假設(shè)有一個(gè)編譯好的C++程序,編譯沒有錯(cuò)誤,但是運(yùn)行時(shí)報(bào)錯(cuò),報(bào)錯(cuò)如下:你正在調(diào)用一個(gè)純虛函數(shù)(Pure virtual function call error),請(qǐng)問導(dǎo)致這個(gè)錯(cuò)誤的原因可能是什么?

純虛函數(shù)調(diào)用錯(cuò)誤一般由以下幾種原因?qū)е拢?/strong>

  • 從基類構(gòu)造函數(shù)直接調(diào)用虛函數(shù)。(直接調(diào)用是指函數(shù)內(nèi)部直接調(diào)用虛函數(shù))
  • 從基類析構(gòu)函數(shù)直接調(diào)用虛函數(shù)。
  • 從基類構(gòu)造函數(shù)間接調(diào)用虛函數(shù)。(間接調(diào)用是指函數(shù)內(nèi)部調(diào)用其他的非虛函數(shù),其內(nèi)部直接或間接地調(diào)用了虛函數(shù))
  • 從基類析構(gòu)函數(shù)間接調(diào)用虛函數(shù)。
  • 通過懸空指針調(diào)用虛函數(shù)。

注意:其中1,2編譯器會(huì)檢測(cè)到此類錯(cuò)誤。3,4,5編譯器無(wú)法檢測(cè)出此類情況,會(huì)在運(yùn)行時(shí)報(bào)錯(cuò)。

(1)虛函數(shù)表vtbl

編譯器在編譯時(shí)期為每個(gè)帶虛函數(shù)的類創(chuàng)建一份虛函數(shù)表

實(shí)例化對(duì)象時(shí), 編譯器自動(dòng)將類對(duì)象的虛表指針指向這個(gè)虛函數(shù)表

(2)構(gòu)造一個(gè)派生類對(duì)象的過程

1.構(gòu)造基類部分:

  • 構(gòu)造虛表指針,將實(shí)例的虛表指針指向基類的vtbl
  • 構(gòu)造基類的成員變量
  • 執(zhí)行基類的構(gòu)造函數(shù)函數(shù)體

2.遞歸構(gòu)造派生類部分:

  • 將實(shí)例的虛表指針指向派生類vtbl
  • 構(gòu)造派生類的成員變量
  • 執(zhí)行派生類的構(gòu)造函數(shù)體

(3)析構(gòu)一個(gè)派生類對(duì)象的過程

1.遞歸析構(gòu)派生類部分:

  • 將實(shí)例的虛表指針指向派生類vtbl
  • 執(zhí)行派生類的析構(gòu)函數(shù)體
  • 析構(gòu)派生類的成員變量(這里的執(zhí)行函數(shù)體,析構(gòu)派生類成員變量,兩者的順序和構(gòu)造的步驟是相反的)

2.析構(gòu)基類部分:

  • 將實(shí)例的虛表指針指向基類的vtbl
  • 執(zhí)行基類的析構(gòu)函數(shù)函數(shù)體
  • 析構(gòu)基類的成員變量

構(gòu)造函數(shù)和析構(gòu)函數(shù)執(zhí)行函數(shù)體時(shí),實(shí)例的虛函數(shù)表指針,指向構(gòu)造函數(shù)和析構(gòu)函數(shù)本身所屬的類的虛函數(shù)表,此時(shí)執(zhí)行的虛函數(shù),即調(diào)用的本身的該類本身的虛函數(shù),下面是一個(gè)【間接調(diào)用】的栗子:基類中的析構(gòu)函數(shù)中,調(diào)用純虛函數(shù)(該虛函數(shù)就在基類中定義)。

#include <iostream>
using namespace std;

class Parent {
public:
	//純虛函數(shù)
    virtual void virtualFunc() = 0;
    void helper() {
        virtualFunc();
    }
    virtual ~Parent(){
        helper();
    }
};

class Child : public Parent{
    public:
    void virtualFunc() {
        cout << "Child" << endl;
    }
    virtual ~Child(){}
};


int main() {
    Child child;
	//system("pause");
    return 0;
}

運(yùn)行時(shí)報(bào)錯(cuò)libc++abi.dylib: Pure virtual function called

在這里插入圖片描述

2.2 真題二

在構(gòu)造實(shí)例過程當(dāng)中一部分是初始化列表一部分是在函數(shù)體內(nèi),你能說(shuō)一下這些的順序是什么?差別是什么和this指針構(gòu)造的順序

順序:

(1)初始化列表中的先初始化。

(2)執(zhí)行函數(shù)體代碼。

  • 執(zhí)行類中函數(shù)體,如執(zhí)行構(gòu)造函數(shù)時(shí),所有成員已經(jīng)初始化完畢了;
  • this指針屬于對(duì)象,而對(duì)象還沒構(gòu)造完成前,若使用this指針,編譯器會(huì)無(wú)法識(shí)別。在初始化列表中顯然不能使用this指針,注意:在構(gòu)造函數(shù)體內(nèi)部可以使用this指針。

構(gòu)造函數(shù)的執(zhí)行可以分成兩個(gè)階段:

  • 初始化階段:所有類類型的成員都會(huì)在初始化階段初始化,即使該成員沒有出現(xiàn)在構(gòu)造函數(shù)的初始化列表中。
  • 計(jì)算賦值階段:一般用于執(zhí)行構(gòu)造函數(shù)體內(nèi)的賦值操作。
#include <iostream>
using namespace std;

class Test1 {
public:
    Test1(){
    	cout << "Construct Test1" << endl;
    }
	//拷貝構(gòu)造函數(shù)
    Test1& operator = (const Test1& t1) {
    	cout << "Assignment for Test1" << endl;
        this->a = t1.a;
        return *this;
    }
    int a ;
};

class Test2 {
public:
    Test1 test1;
	//Test2的構(gòu)造函數(shù)
    Test2(Test1 &t1) {
    	cout << "構(gòu)造函數(shù)體開始" << endl;
        test1 = t1 ;
        cout << "構(gòu)造函數(shù)體結(jié)束" << endl;
    }
};

int main() {
    Test1 t1;
    Test2 test(t1);
	system("pause");
    return 0;
}

在這里插入圖片描述

分析上面的結(jié)果:

(1)第一行結(jié)果即Test t1實(shí)例化對(duì)象時(shí),執(zhí)行Test1的構(gòu)造函數(shù);

(2)第二行代碼,實(shí)例化Test2對(duì)象時(shí),在執(zhí)行Test2構(gòu)造函數(shù)時(shí),正如上面所說(shuō)的,構(gòu)造函數(shù)的第一步是初始化階段:所有類類型的成員都會(huì)在初始化階段初始化,即使該成員沒有出現(xiàn)在構(gòu)造函數(shù)的初始化列表中。所以Test2在構(gòu)造函數(shù)體執(zhí)行之前已經(jīng)使用了Test1的默認(rèn)構(gòu)造函數(shù)初始化好了t1。打印出Construct Test1。

這里的拷貝構(gòu)造函數(shù)中可以使用this指針,指向當(dāng)前對(duì)象。

(3)第三四五行結(jié)果:執(zhí)行Test2的構(gòu)造函數(shù)。

2.3 真題三

初始化列表的寫法和順序有沒有什么關(guān)系?

構(gòu)造函數(shù)的初始化列表中的前后位置,不影響實(shí)際標(biāo)量的初始化順序。成員初始化的順序和它們?cè)陬愔械亩x順序一致。

必須使用初始化列表的情況:數(shù)據(jù)成員是const、引用,或者屬于某種未提供默認(rèn)構(gòu)造函數(shù)的類類型。

2.4 真題四

在普通的函數(shù)當(dāng)中調(diào)用虛函數(shù)和在構(gòu)造函數(shù)當(dāng)中調(diào)用虛函數(shù)有什么區(qū)別?

普調(diào)函數(shù)當(dāng)中調(diào)用虛函數(shù)是希望運(yùn)行時(shí)多態(tài)。而在構(gòu)造函數(shù)當(dāng)中不應(yīng)該去調(diào)用虛函數(shù)因?yàn)闃?gòu)造函數(shù)當(dāng)中調(diào)用的就是本類型當(dāng)中的虛函數(shù),無(wú)法達(dá)到運(yùn)行時(shí)多態(tài)的作用。

2.5 真題五

成員變量,虛函數(shù)表指針的位置是怎么排布?

如果一個(gè)類帶有虛函數(shù),那么該類實(shí)例對(duì)象的內(nèi)存布局如下:

  • 首先是一個(gè)虛函數(shù)指針,
  • 接下來(lái)是該類的成員變量,按照成員在類當(dāng)中聲明的順序排布,整體對(duì)象的大小由于內(nèi)存對(duì)齊會(huì)有空白補(bǔ)齊。
  • 其次如果基類沒有虛函數(shù)但是子類含有虛函數(shù):
    • 此時(shí)內(nèi)存子類對(duì)象的內(nèi)存排布也是先虛函數(shù)表指針再各個(gè)成員。

如果將子類指針轉(zhuǎn)換成基類指針此時(shí)編譯器會(huì)根據(jù)偏移做轉(zhuǎn)換。在visual studio,x64環(huán)境下測(cè)試,下面的Parent p = Child();是父類對(duì)象,由子類來(lái)實(shí)例化對(duì)象。

#include <iostream>
using namespace std;

class Parent{
public:
    int a;
    int b;
};

class Child:public Parent{
public:
    virtual void test(){}
    int c;
};

int main() {
    Child c = Child();
    Parent p = Child();
    cout << sizeof(c) << endl;//24
    cout << sizeof(p) << endl;//8

    Child* cc = new Child();
    Parent* pp = cc;
    cout << cc << endl;//0x7fbe98402a50
    cout << pp << endl;//0x7fbe98402a58
	cout << endl << "子類對(duì)象abc成員地址:" << endl;
    cout << &(cc->a) << endl;//0x7fbe98402a58
    cout << &(cc->b) << endl;//0x7fbe98402a5c
    cout << &(cc->c) << endl;//0x7fbe98402a60
	system("pause");
    return 0;
}

結(jié)果如下:

24
8
0000013AC9BA4A40
0000013AC9BA4A48

子類對(duì)象abc成員地址:
0000013AC9BA4A48
0000013AC9BA4A4C
0000013AC9BA4A50
請(qǐng)按任意鍵繼續(xù). . .

分析上面的結(jié)果:

(1)第一行24為子類對(duì)象的大小,首先是虛函數(shù)表指針8B,然后是2個(gè)繼承父類的int型數(shù)值,還有1個(gè)是該子類本身的int型數(shù)值,最后的4是填充的。

(2)第二行的8為父類對(duì)象的大小,該父類對(duì)象由子類初始化,含有2個(gè)int型成員變量。

(3)子類指針cc指向又new出來(lái)的子類對(duì)象(第三個(gè)),然后父類指針pp指向這個(gè)子類對(duì)象,這兩個(gè)指針的值:

  • 父類指針pp值:0000013AC9BA4A48
  • 子類指針cc值:0000013AC9BA4A40

即發(fā)現(xiàn)如之前所說(shuō)的:如果將子類指針轉(zhuǎn)換成基類指針此時(shí)編譯器會(huì)根據(jù)偏移做轉(zhuǎn)換。我測(cè)試環(huán)境是64位,所以指針為8個(gè)字節(jié)。轉(zhuǎn)換之后pp和cc相差一個(gè)虛表指針的偏移。

(4)&(cc->a)的值即 0000013AC9BA4A48,和pp值是一樣的,注意前面的 0000013AC9BA4A40到0000013AC9BA4A47其實(shí)就是子類對(duì)象的虛函數(shù)表指針了。

三、小結(jié)

阿里??嫉腃++的問題集中在以下幾點(diǎn):

  • 虛函數(shù)的實(shí)現(xiàn)
  • 虛函數(shù)使用出現(xiàn)的問題原因
  • 帶有虛函數(shù)的類對(duì)象的構(gòu)造和析構(gòu)過程
  • 對(duì)象的內(nèi)存布局
  • 虛函數(shù)的缺點(diǎn):相比普通函數(shù),虛函數(shù)調(diào)用需要2次跳轉(zhuǎn)(即需要先找到對(duì)象的虛函數(shù)表,再查找該表項(xiàng),即虛函數(shù)指針,即真正的虛函數(shù)地址),會(huì)降低CPU緩存的命中率。運(yùn)行時(shí)綁定,編譯器不好優(yōu)化。

總結(jié)

本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!    

相關(guān)文章

  • C語(yǔ)言求質(zhì)數(shù)的幾種簡(jiǎn)單易懂方式

    C語(yǔ)言求質(zhì)數(shù)的幾種簡(jiǎn)單易懂方式

    這篇文章主要介紹了C語(yǔ)言求質(zhì)數(shù)的幾種簡(jiǎn)單易懂方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 詳解C++ new-handler機(jī)制

    詳解C++ new-handler機(jī)制

    這篇文章主要介紹了C++ new-handler機(jī)制的相關(guān)資料,幫助大家更好的理解和使用c++,感興趣的朋友可以了解下
    2020-11-11
  • unsigned中無(wú)符號(hào)是什么詳析

    unsigned中無(wú)符號(hào)是什么詳析

    unsigned為“無(wú)符號(hào)”的意思,unsigned,zerofill既為非負(fù)數(shù),用此類型可以增加數(shù)據(jù)長(zhǎng)度,下面這篇文章主要給大家介紹了關(guān)于unsigned中無(wú)符號(hào)是什么的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • C++中VTK9.3.0刻度標(biāo)簽重疊的問題記錄

    C++中VTK9.3.0刻度標(biāo)簽重疊的問題記錄

    這篇文章主要介紹了C++中VTK9.3.0刻度標(biāo)簽重疊的問題,本文采用VTK9.3.0版本,其他版本如VKT8.0亦有同樣的問題,需要的朋友可以參考下
    2024-06-06
  • C++常對(duì)象精講_const關(guān)鍵字的用法

    C++常對(duì)象精講_const關(guān)鍵字的用法

    用const修飾的聲明數(shù)據(jù)成員稱為常數(shù)據(jù)成員。變量或?qū)ο蟊?const修飾后其值不能被更新。因此被const修飾的變量或?qū)ο蟊仨氁M(jìn)行初始化
    2013-10-10
  • 講解C++中的枚舉類型以及聲明新類型的方法

    講解C++中的枚舉類型以及聲明新類型的方法

    這篇文章主要介紹了講解C++中的枚舉類型以及聲明新類型的方法,是C預(yù)言入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-09-09
  • C++實(shí)現(xiàn)截圖截屏的示例代碼

    C++實(shí)現(xiàn)截圖截屏的示例代碼

    本文主要介紹了C++實(shí)現(xiàn)截圖截屏的示例代碼,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • c++冒泡排序詳解

    c++冒泡排序詳解

    冒泡排序(Bubble Sort),是一種計(jì)算機(jī)科學(xué)領(lǐng)域的較簡(jiǎn)單的排序算法。它重復(fù)地走訪過要排序的數(shù)列,一次比較兩個(gè)元素,如果他們的順序錯(cuò)誤就把他們交換過來(lái)。走訪數(shù)列的工作是重復(fù)地進(jìn)行直到?jīng)]有再需要交換,也就是說(shuō)該數(shù)列已經(jīng)排序完成。
    2017-05-05
  • C語(yǔ)言函數(shù)超詳細(xì)講解上篇

    C語(yǔ)言函數(shù)超詳細(xì)講解上篇

    函數(shù)是一組一起執(zhí)行一個(gè)任務(wù)的語(yǔ)句。每個(gè)?C?程序都至少有一個(gè)函數(shù),即主函數(shù)?main()?,所有簡(jiǎn)單的程序都可以定義其他額外的函數(shù),函數(shù)我們分兩篇來(lái)講解,接下來(lái)開始第一篇
    2022-04-04
  • C++利用類實(shí)現(xiàn)矩陣的數(shù)乘,乘法以及點(diǎn)乘

    C++利用類實(shí)現(xiàn)矩陣的數(shù)乘,乘法以及點(diǎn)乘

    這篇文章主要為大家詳細(xì)介紹了C++如何利用類實(shí)現(xiàn)矩陣的數(shù)乘,乘法以及點(diǎn)乘,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C++有一定幫助,需要的可以參考一下
    2022-11-11

最新評(píng)論

芷江| 桦川县| 和平区| 余江县| 浦北县| 老河口市| 南康市| 濉溪县| 太原市| 资兴市| 柳河县| 沁阳市| 江达县| 灵璧县| 三亚市| 仪征市| 师宗县| 定襄县| 临江市| 通河县| 乐清市| 东辽县| 会昌县| 沙坪坝区| 同心县| 甘泉县| 钦州市| 咸丰县| 凤翔县| 建水县| 长宁县| 枣阳市| 繁昌县| 集安市| 砚山县| 黄石市| 上蔡县| 逊克县| 正安县| 岳阳市| 玉树县|