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

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

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

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

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

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

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

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

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

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

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

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

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

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

二師兄:(起開,我要開始裝逼了?。〤++主要使用了虛指針和虛表來實現(xiàn)多態(tài)。在擁有虛函數(shù)的對象中,包含一個虛指針(virtual pointer)(一般位于對象所在內(nèi)存的起始位置),這個虛指針指向一個虛表(virtual table),虛表中記錄了虛函數(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é) 到下一個指針 fun2
    PF* pf3 = pf1 + 2;  //偏移16字節(jié) 到下下一個指針 fun3
    (*pf1)();   //Foo::fun1 or Goo::fun1 取決于pf的真實類型
    (*pf2)();   //Foo::fun2
    (*pf3)();   //Foo::fun3 or Goo::fun3 取決于pf的真實類型
}
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)初始化虛表時,會把當(dāng)前類override的函數(shù)地址寫到虛表中(Goo::fun1Goo::fun3),對于基類中的虛函數(shù)但是派生類中沒有override,則會把基類的函數(shù)地址寫到虛表中(Foo::fun2),在調(diào)用函數(shù)的時候,會通過虛指針轉(zhuǎn)到虛表,并根據(jù)虛函數(shù)的偏移得到真實函數(shù)地址,從而實現(xiàn)多態(tài)。

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

二師兄:多繼承內(nèi)存布局類似,只不過會多幾個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
}

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

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

二師兄:因為B和C各繼承了一份A,當(dāng)D繼承B和C的時候就會有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)用從哪個類中繼承的val變量
    d.fun(); 	//編譯失敗,不知道調(diào)用從哪個類中繼承的fun函數(shù)
}

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

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

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

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

#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
}

二師兄:此時在對象d中,只包含了一個val和兩個虛指針,成員變量的冗余問題得到解決。

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

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

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

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

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

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

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

#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();  //編譯錯誤
    using Fun = void(*)();
    size_t* virtual_point = (size_t*)&f;
    Fun* fun = (Fun*)*virtual_point;
    (*fun)();
}

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

總結(jié) 

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

相關(guān)文章

  • c++模擬實現(xiàn)string類詳情

    c++模擬實現(xiàn)string類詳情

    這篇文章主要介紹了c++模擬實現(xiàn)string類詳情,string表示可變長的字符序列,使用string類型必須首先包含string頭文件。作為標(biāo)準(zhǔn)庫的一部分,string定義在命名空間std中,下面進(jìn)入文章一起看看詳細(xì)內(nèi)容吧
    2022-01-01
  • Qt?QtCreator添加自定義注釋的實現(xiàn)方法

    Qt?QtCreator添加自定義注釋的實現(xiàn)方法

    在寫代碼的時候我們?yōu)榱艘?guī)范化,一般會加文件注釋、類注釋和函數(shù)注釋,本文主要介紹了Qt?QtCreator添加自定義注釋的實現(xiàn)方法,具有一定的參考價值,感興趣的可以了解一下
    2023-11-11
  • C語言實現(xiàn)學(xué)生消費管理系統(tǒng)

    C語言實現(xiàn)學(xué)生消費管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)學(xué)生消費管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • C語言形參和實參的區(qū)別詳解

    C語言形參和實參的區(qū)別詳解

    在函數(shù)定義和調(diào)用過程中,形參和實參是非常重要的概念,本文主要介紹了C語言形參和實參的區(qū)別,具有一定的參考價值,感興趣的可以了解一下
    2023-05-05
  • C和C++混合編程問題

    C和C++混合編程問題

    這篇文章主要介紹了C和C++混合編程問題,需要的朋友可以參考下
    2015-10-10
  • C++之動態(tài)數(shù)組vector解讀

    C++之動態(tài)數(shù)組vector解讀

    這篇文章主要介紹了C++之動態(tài)數(shù)組vector解讀,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-06-06
  • C++指針數(shù)組、數(shù)組指針、數(shù)組名及二維數(shù)組技巧匯總

    C++指針數(shù)組、數(shù)組指針、數(shù)組名及二維數(shù)組技巧匯總

    這篇文章主要介紹了C++指針數(shù)組、數(shù)組指針、數(shù)組名及二維數(shù)組技巧匯總,對于深入理解C++數(shù)組與指針來說非常重要,需要的朋友可以參考下
    2014-08-08
  • 使用C語言編寫一個關(guān)機(jī)惡搞小程序

    使用C語言編寫一個關(guān)機(jī)惡搞小程序

    system函數(shù)的參數(shù)是"shutdown"時,它將會執(zhí)行系統(tǒng)的關(guān)機(jī)命令,所以本文將利用這一特點制作一個關(guān)機(jī)惡搞小程序,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-02-02
  • 對比C語言中execv相關(guān)的執(zhí)行文件的三個函數(shù)

    對比C語言中execv相關(guān)的執(zhí)行文件的三個函數(shù)

    這篇文章主要介紹了對比C語言中execv相關(guān)的執(zhí)行文件的三個函數(shù),分別為execv()函數(shù)和execve()函數(shù)以及execvp()函數(shù),需要的朋友可以參考下
    2015-08-08
  • c++實現(xiàn)reactor高并發(fā)服務(wù)器的詳細(xì)教程

    c++實現(xiàn)reactor高并發(fā)服務(wù)器的詳細(xì)教程

    這篇文章主要介紹了c++從零實現(xiàn)reactor高并發(fā)服務(wù)器,包括環(huán)境準(zhǔn)備和基礎(chǔ)知識介紹,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-03-03

最新評論

应用必备| 揭东县| 楚雄市| 麻阳| 璧山县| 策勒县| 佛冈县| 青浦区| 会宁县| 巩留县| 茌平县| 商洛市| 德惠市| 乐安县| 津市市| 永州市| 五大连池市| 伽师县| 青河县| 滦平县| 大兴区| 吉林省| 宣化县| 林周县| 柳江县| 涟源市| 绩溪县| 会宁县| 华容县| 宝山区| 华亭县| 安宁市| 南江县| 百色市| 同江市| 奉新县| 涞水县| 始兴县| 鹿邑县| 拜泉县| 砀山县|