欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++面試八股文之override和finial關(guān)鍵字有何作用

 更新時(shí)間:2023年06月23日 09:04:17   作者:binarch  
C++11中的override和final關(guān)鍵字是為了增強(qiáng)代碼的編譯時(shí)類型檢查和面向?qū)ο笤O(shè)計(jì)中的繼承機(jī)制,下面這篇文章主要給大家介紹了關(guān)于C++面試八股文之override和finial關(guān)鍵字有何作用的相關(guān)資料,需要的朋友可以參考下

某日二師兄參加X(jué)XX科技公司的C++工程師開(kāi)發(fā)崗位第22面: (二師兄好苦逼,節(jié)假日還在面試。。。)

面試官:C++的繼承了解嗎?

二師兄:(不好意思,你面到我的強(qiáng)項(xiàng)了。。)了解一些。

面試官:什么是虛函數(shù),為什么需要虛函數(shù)?

二師兄:虛函數(shù)允許在基類中定義一個(gè)函數(shù),然后在派生類中進(jìn)行重寫(xiě)(override)。

二師兄:主要是為了實(shí)現(xiàn)面向?qū)ο笾械娜筇匦灾欢鄳B(tài)。多態(tài)允許在子類中重寫(xiě)父類的虛函數(shù),同樣的函數(shù)在子類和父類實(shí)現(xiàn)不同的形態(tài),簡(jiǎn)稱為多態(tài)。

面試官:你知道overridefinial關(guān)鍵字的作用嗎?

二師兄:override關(guān)鍵字告訴編譯器,這個(gè)函數(shù)一定會(huì)重寫(xiě)父類的虛函數(shù),如果父類沒(méi)有這個(gè)虛函數(shù),則無(wú)法通過(guò)編譯。此關(guān)鍵字可省略,但不建議省略。

二師兄:finial關(guān)鍵字告訴編譯器,這個(gè)函數(shù)到此為止,如果后續(xù)有類繼承當(dāng)前類,也不能再重寫(xiě)此函數(shù)。

二師兄:這兩個(gè)關(guān)鍵字都是C++11引入的,為了提升C++面向?qū)ο缶幋a的安全性。

面試官:你知道多態(tài)是怎么實(shí)現(xiàn)的嗎?

二師兄:(起開(kāi),我要開(kāi)始裝逼了?。〤++主要使用了虛指針和虛表來(lái)實(shí)現(xiàn)多態(tài)。在擁有虛函數(shù)的對(duì)象中,包含一個(gè)虛指針(virtual pointer)(一般位于對(duì)象所在內(nèi)存的起始位置),這個(gè)虛指針指向一個(gè)虛表(virtual table),虛表中記錄了虛函數(shù)的真實(shí)地址。

#include <iostream>
struct Foo
{
    size_t a = 42;
    virtual void fun1() {std::cout <<"Foo::fun1" << std::endl;}
    virtual void fun2() {std::cout <<"Foo::fun2" << std::endl;}
    virtual void fun3() {std::cout <<"Foo::fun3" << std::endl;}
};
struct Goo: Foo{
    size_t b = 1024;
    virtual void fun1() override {std::cout <<"Goo::fun1" << std::endl;}
    virtual void fun3() override {std::cout <<"Goo::fun3" << std::endl;}
};
using PF = void(*)();
void test(Foo* pf)
{
    size_t* virtual_point = (size_t*)pf;
    PF* pf1 = (PF*)*virtual_point;  
    PF* pf2 = pf1 + 1;  //偏移8字節(jié) 到下一個(gè)指針 fun2
    PF* pf3 = pf1 + 2;  //偏移16字節(jié) 到下下一個(gè)指針 fun3
    (*pf1)();   //Foo::fun1 or Goo::fun1 取決于pf的真實(shí)類型
    (*pf2)();   //Foo::fun2
    (*pf3)();   //Foo::fun3 or Goo::fun3 取決于pf的真實(shí)類型
}
int main(int argc, char const *argv[])
{
    Foo* fp = new Foo;
    test(fp);
    fp = new Goo;
    test(fp);
    size_t* virtual_point = (size_t*)fp;
    size_t* ap = virtual_point + 1;
    size_t* bp = virtual_point + 2;
    std::cout << *ap << std::endl;  //42
    std::cout << *bp << std::endl;  //1024
}

二師兄:當(dāng)初始化虛表時(shí),會(huì)把當(dāng)前類override的函數(shù)地址寫(xiě)到虛表中(Goo::fun1、Goo::fun3),對(duì)于基類中的虛函數(shù)但是派生類中沒(méi)有override,則會(huì)把基類的函數(shù)地址寫(xiě)到虛表中(Foo::fun2),在調(diào)用函數(shù)的時(shí)候,會(huì)通過(guò)虛指針轉(zhuǎn)到虛表,并根據(jù)虛函數(shù)的偏移得到真實(shí)函數(shù)地址,從而實(shí)現(xiàn)多態(tài)。

面試官:不錯(cuò)。上圖你畫(huà)出了單一繼承的內(nèi)存布局,那多繼承呢?

二師兄:多繼承內(nèi)存布局類似,只不過(guò)會(huì)多幾個(gè)virtual pointer。

#include <iostream>
struct Foo1
{
    size_t a = 42;
    virtual void fun1() {std::cout <<"Foo1::fun1" << std::endl;}
    virtual void fun2() {std::cout <<"Foo1::fun2" << std::endl;}
    virtual void fun3() {std::cout <<"Foo1::fun3" << std::endl;}
};
struct Foo2{
    size_t b = 1024;
    virtual void fun4()  {std::cout <<"Foo2::fun4" << std::endl;}
    virtual void fun5()  {std::cout <<"Foo2::fun5" << std::endl;}
};
struct Foo3{
    size_t c = 0;
    virtual void fun6()  {std::cout <<"Foo3::fun1" << std::endl;}
    virtual void fun7()  {std::cout <<"Foo3::fun3" << std::endl;}
};
struct Goo: public Foo1, public Foo2, public Foo3
{
    virtual void fun2() override {std::cout <<"Goo::fun2" << std::endl;}
    virtual void fun6() override {std::cout <<"Goo::fun6" << std::endl;}
};
int main(int argc, char const *argv[])
{
    Goo g;
    g.fun1();   //Foo1::fun1
    g.fun2();   //Goo::fun2
    g.fun3();   //Foo1::fun3
    g.fun4();   //Foo2::fun4
    g.fun5();   //Foo2::fun5
    g.fun6();   //Goo::fun6
    g.fun7();   //Foo3::fun7
}

面試官:你知道什么是菱形繼承嗎?菱形繼承會(huì)引發(fā)什么問(wèn)題?如何解決?

二師兄:菱形繼承(Diamond Inheritance)是指在繼承層次結(jié)構(gòu)中,如果兩個(gè)不同的子類B和C繼承自同一個(gè)父類A,而又有一個(gè)類D同時(shí)繼承B和C,這種繼承關(guān)系被稱為菱形繼承。

二師兄:因?yàn)锽和C各繼承了一份A,當(dāng)D繼承B和C的時(shí)候就會(huì)有2份A;

#include <iostream>
struct A
{
    int val = 42;
    virtual void fun(){std::cout <<"A::fun" << std::endl;}
};
struct B: public A{ void fun() override{std::cout <<"B::fun" << std::endl;}};
struct C: public A{ void fun() override{std::cout <<"C::fun" << std::endl;}};
struct D: public B, public C{void fun() override{std::cout <<"D::fun" << std::endl;}};
int main(int argc, char const *argv[])
{
   	D d;
    std::cout << d.val << std::endl;	//編譯失敗,不知道調(diào)用從哪個(gè)類中繼承的val變量
    d.fun(); 	//編譯失敗,不知道調(diào)用從哪個(gè)類中繼承的fun函數(shù)
}

二師兄:解決的辦法有兩種,一種是在調(diào)用符之前加上父類限定符:

std::cout << d.B::val << std::endl; //42
d.C::fun();     //C::fun

二師兄:但這里并沒(méi)有解決數(shù)據(jù)冗余的問(wèn)題,因?yàn)镈中有B和C,而B(niǎo)和C各有一個(gè)虛表和一個(gè)int類型的成員變量,所以sizeof(D)的大小是32(x86_64架構(gòu),考慮到內(nèi)存對(duì)齊)。

二師兄:所幸在C++11引入了虛繼承(Virtual Inheritance)機(jī)制,從源頭上解決了這個(gè)問(wèn)題:

#include <iostream>
struct A
{
    int val = 42;
    virtual void fun(){std::cout <<"A::fun" << std::endl;}
};
struct B: virtual public A{ void fun() override{std::cout <<"B::fun" << std::endl;}};
struct C: virtual public A{ void fun() override{std::cout <<"C::fun" << std::endl;}};
struct D: public B, public C{void fun() override{std::cout <<"D::fun" << std::endl;}};
int main(int argc, char const *argv[])
{
    D d;
    std::cout << d.val << std::endl; //42
    d.fun();     //D::fun
}

二師兄:此時(shí)在對(duì)象d中,只包含了一個(gè)val和兩個(gè)虛指針,成員變量的冗余問(wèn)題得到解決。

面試官:一般我們認(rèn)為多態(tài)會(huì)影響性能,你舉得為什么影響性能?

二師兄:大多數(shù)人認(rèn)為,虛函數(shù)的調(diào)用會(huì)先通過(guò)虛指針跳到虛函數(shù)表,然后通過(guò)偏移確定函數(shù)真實(shí)地址,再跳轉(zhuǎn)到地址執(zhí)行,是間接調(diào)用導(dǎo)致了性能損失。

二師兄:但實(shí)際上無(wú)法內(nèi)聯(lián)才是虛函數(shù)性能低于正常函數(shù)的主要原因。由于多態(tài)是運(yùn)行時(shí)特征,在編譯時(shí)編譯器并不知道指針指向的函數(shù)地址,所以無(wú)法被內(nèi)聯(lián)。同時(shí)跳轉(zhuǎn)到特定地址執(zhí)行函數(shù)可能引發(fā)的L1 cache miss(空間局部性不好),這也會(huì)影響性能。

面試官:虛函數(shù)的調(diào)用一定是非內(nèi)聯(lián)的嗎?

二師兄:不是?,F(xiàn)代編譯器很聰明,如果編譯器能夠在編譯時(shí)推斷出真實(shí)的函數(shù),可能會(huì)直接內(nèi)聯(lián)這個(gè)虛函數(shù)。虛函數(shù)的調(diào)用是否內(nèi)聯(lián)取決于編譯器的實(shí)現(xiàn)和上下文。

面試官:你覺(jué)得多態(tài)在安全性上有沒(méi)有什么問(wèn)題?

二師兄:的確是有的。當(dāng)我們把類中的虛函數(shù)定義為private的時(shí)候,雖然我們不能通過(guò)類的對(duì)象去訪問(wèn)這個(gè)函數(shù),但我們知道這個(gè)函數(shù)就在虛函數(shù)表中,可以通過(guò)特殊的方法(上文中已經(jīng)給出示例)訪問(wèn)它:

#include <iostream>
struct Foo
{
private:
    virtual void fun() {std::cout << "Foo::fun" << std::endl;}
};
int main(int argc, char const *argv[])
{
    Foo f;
    //f.fun();  //編譯錯(cuò)誤
    using Fun = void(*)();
    size_t* virtual_point = (size_t*)&f;
    Fun* fun = (Fun*)*virtual_point;
    (*fun)();
}

面試官:好的,今天的面試到這里就結(jié)束了,請(qǐng)回去等通知吧。

總結(jié) 

到此這篇關(guān)于C++面試八股文之override和finial關(guān)鍵字有何作用的文章就介紹到這了,更多相關(guān)C++ override和finial關(guān)鍵字的作用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語(yǔ)言編程內(nèi)存分配通訊錄靜態(tài)實(shí)現(xiàn)示例代碼教程

    C語(yǔ)言編程內(nèi)存分配通訊錄靜態(tài)實(shí)現(xiàn)示例代碼教程

    這篇文章主要為大家介紹了C語(yǔ)言編程實(shí)現(xiàn)靜態(tài)的通訊錄示例代碼教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2021-10-10
  • Qt中QDateTimeEdit的具體使用

    Qt中QDateTimeEdit的具體使用

    本文主要介紹了Qt中QDateTimeEdit的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • C語(yǔ)言實(shí)現(xiàn)計(jì)算雙色球的中獎(jiǎng)率

    C語(yǔ)言實(shí)現(xiàn)計(jì)算雙色球的中獎(jiǎng)率

    這篇文章主要為大家詳細(xì)介紹了如何利用C語(yǔ)言實(shí)現(xiàn)計(jì)算雙色球的中獎(jiǎng)率,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-12-12
  • C++?Cartographer源碼中關(guān)于傳感器的數(shù)據(jù)傳遞實(shí)現(xiàn)

    C++?Cartographer源碼中關(guān)于傳感器的數(shù)據(jù)傳遞實(shí)現(xiàn)

    這篇文章主要介紹了C++?Cartographer源碼中關(guān)于傳感器的數(shù)據(jù)傳遞實(shí)現(xiàn),前面已經(jīng)談到了Cartographer中添加軌跡的方法和傳感器的數(shù)據(jù)流動(dòng)走向。發(fā)現(xiàn)在此調(diào)用了LaunchSubscribers這個(gè)函數(shù)來(lái)訂閱相關(guān)傳感器數(shù)據(jù)
    2023-03-03
  • C++操作文件進(jìn)行讀取、刪除、修改指定行

    C++操作文件進(jìn)行讀取、刪除、修改指定行

    今天小編就為大家分享一篇關(guān)于C++操作文件進(jìn)行讀取、刪除、修改指定行,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-12-12
  • C++下如何將TensorFlow模型封裝成DLL供C#調(diào)用

    C++下如何將TensorFlow模型封裝成DLL供C#調(diào)用

    這篇文章主要介紹了C++下如何將TensorFlow模型封裝成DLL供C#調(diào)用問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • C語(yǔ)言實(shí)現(xiàn)BMP圖像閉運(yùn)算處理

    C語(yǔ)言實(shí)現(xiàn)BMP圖像閉運(yùn)算處理

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)BMP圖像閉運(yùn)算處理,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • C++ 的三種訪問(wèn)權(quán)限與三種繼承方式

    C++ 的三種訪問(wèn)權(quán)限與三種繼承方式

    我們知道C++中的類,有三種訪問(wèn)權(quán)限(也稱作訪問(wèn)控制),它們分別是public、protected、private,C++中繼承的方式還有多種。下面通過(guò)本文給大家詳細(xì)介紹,對(duì)c++中的訪問(wèn)權(quán)限和繼承方式感興趣的朋友一起看看吧
    2016-11-11
  • 人臉檢測(cè)中AdaBoost算法詳解

    人臉檢測(cè)中AdaBoost算法詳解

    這篇文章主要為大家詳細(xì)介紹了人臉檢測(cè)中AdaBoost算法的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • C++可執(zhí)行文件絕對(duì)路徑值與VS安全檢查詳解

    C++可執(zhí)行文件絕對(duì)路徑值與VS安全檢查詳解

    這篇文章主要給大家介紹了關(guān)于C++可執(zhí)行文件絕對(duì)路徑值與VS安全檢查的相關(guān)資料,文中通過(guò)圖文以及實(shí)例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C++具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2023-01-01

最新評(píng)論