日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++多态讲解以及常见面试题

發布時間:2024/7/23 c/c++ 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++多态讲解以及常见面试题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

多態的概念

什么是多態
? 多態就是在不同繼承關系的類對象,去調用同一函數,產生了不同的行為。

實現多態的條件

  • 動態綁定多態(在運行時才知道函數的地址):
  • 調用函數的對象是指針或引用。
    被調用函數必須是虛函數,并且完成了虛函數的重寫。

  • 靜態綁定多態(在編譯時確定函數的地址):
  • 函數重載

    多態的作用

    ??封裝是為了代碼模塊化,繼承是擴展已存在的代碼,他們的目的都是為了 實現代碼的復用,但是多態的目的是為了實現接口的重用,也就是多不管傳遞過來的是哪個類對象,函數都能狗狗通過這個接口調用到適應自己對象的實現方法。
    ??虛函數重寫:子類重寫父類的函數(協變:子類中的返回值和父類中的返回值是父子關系,并且是引用或指針)。如果只在父類中添加virtual關鍵字,子類中的重寫函數也會稱為虛函數,童謠可以構成多態,否則為重定義。

    函數重載、重定義、重寫的區別:

  • 函數的重載:在相同的作用域中,兩個函數的參數不同,函數名相同,構成函數重載。
  • 函數重定義:子類中有父類的同名函數,繼承自父類的函數被隱藏,子類調用重寫后的。
  • 函數的重寫:子類與父類的虛函數函數名、參數、返回值相同的函數,構成函數重寫。
  • 虛函數和純虛函數

    ??虛函數就是在類的成員函數錢錢添加了virtual關鍵字。主要是為了實現多態,通過一張虛函數表來實現。它允許子類重寫來自父類的成員函數。
    ??純虛函數就是在基類中只對對應的虛函數進行聲明,在最后加=0,定義純虛函數的類是一個抽象類,抽象類不能被實例化,它體現的是接口繼承,子類只是繼承了這個接口的形式,不需要使用他里面的功能,要實現自己的功能。在子類中必須實現父類的純虛函數,如果不實現父類的純虛函數,這個子類也是一個抽象類,同樣不能區實例化對象。
    ??那么什么是抽象類呢?抽象類就是包含純虛函數的類,這個類不能被實例化,因為類定義的不完整,成員函數都沒有實現,這種類只是為了接口繼承的實現,繼承他的子類并不想去用它,子類要實現自己的功能。
    ??無論是虛函數還是純虛函數,都是在基類中為派生類提供編程接口,面向對象最核心的思想就是對接口編程,而不是對實現編程,在C++中,就是使用繼承和多態來事項這種思想。如果想讓基類為派生類提供缺省的處理方法,那么就將這個函數設為虛函數,如果是想讓派生類必須重寫該虛函數,就將這個函數設為純虛函數。

    1、虛函數和純虛函數可以定義在同一個類中,一旦某個類包含了純虛函數,這個類就是一個抽象類。
    2、虛函數可以直接被使用,但是純虛函數必須要在派生類中實現之后才可以使用,一i那位純虛函數在積累中只聲明沒有定義,所以無法直接使用。
    3、虛函數和純虛函數都可以在子了中被重寫,一墮胎的形式被調用。
    4、虛函數和純虛函數都是為了實現接口繼承而出現。
    5、虛函數的定義:virtual + 函數純虛函數定義:virtual + 函數 + =0;
    6、虛函數和純虛函數都不能設為static,因為static在編譯的時候就要被綁定,但是虛函數和純虛函數實在運行時在確定的。

    虛函數表

    ??虛函數表是一個函數指針數組,在末尾存放的時一個空指針nullptr,在VS中存放在代碼段,在虛函數表中只存放虛函數執政,他不存放普通函數的指針,將新創建的虛函數指針存放在虛函數表末尾。
    ??虛標指針:存放在對象模型中,在32位機上,存放在對象模型的頭4個字節中。

    單繼承中的虛表

    ??在單繼承中所有的虛函數都存放在虛表中,如果有被重寫的,直接將虛表中的虛函數指針換成重寫后的虛函數指針即可,如果在子類中的添加了新的虛函數,按照新的虛函數的聲明順序將其添加到虛表中。在虛表中,先添加父類的虛函數指針,再添加子類的虛函數指針。

    多繼承中的虛表
    #include <iostream> using namespace std; class base1 { public:virtual void func1(){cout << "base1::func1" << endl;}virtual void func2(){cout << "base1::func2" << endl;} private:int b1; }; class base2 { public:virtual void func1(){cout << "base2::func1" << endl;}virtual void func2(){cout << "base2::func2" << endl;} private:int b2; }; class derive:public base1, public base2 { public:virtual void func1(){cout << "derive::func1" << endl;}virtual void func3(){cout << "derive::func3" << endl;} private:int d1; }; typedef void(*VFPTR)(); //函數指針 void printFunc(VFPTR* vftable) {cout << "虛表地址" << vftable << endl;for (int i = 0; (*vftable) != nullptr; ++i){cout << "第" << i << "個函數地址" << *vftable << "--->";(*vftable)();//調這個函數++vftable;//指針向后走,打印下一個函數地址} }int main() {derive d;//取虛標地址的方法://先取到d的地址,由于虛標指針存放在對象的頭四個字節中,所以要將他轉為int*類型(int* 位四個字節),這樣就可以得到頭四個字節的內容,對這個已經得到的四個字節解引用就可以得到它的值,但現在他是整型的,我們要的是函數指針,所以要將他強轉位函數指針類型的指針就可以得到虛表的地址(VFPTR*)*((int*)&b);//如果要調用虛表中的第一個函數,對他向后偏移1個單位再解引用就可以調用虛表中的第一個函數(*(((VFPTR*)*((int*)&b))+1))();//打印第二個虛標地址//方法一://給出一個base2的指針,讓他存放d的地址,這時候就發生了一個天然的轉換,這個指針中存放的就是第二個虛表的地址base2* pd = &d;//方法二//讓第一個虛表的地址向后偏移base1的大小(VFPTR*)*((int*)((char*)&b+sizeof(base1)))return 0; }

    接口繼承和實現繼承

    ??普通函數的繼承就是一種實現繼承,派生類繼承了基類函數,繼承的是函數的實現。
    ??虛函數的繼承是接口繼承,派生類繼承的是基類函數的接口,目的是為了重寫,從而達成多態,繼承的是接口。如果不是為了實現多態,不要把函數設為虛函數。

    —>常見面試題<—

    總結

    以上是生活随笔為你收集整理的C++多态讲解以及常见面试题的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。