亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C++虛函數表和虛析構介紹

 更新時間:2021年11月12日 10:39:57   作者:學渣的C/C++  
這篇文章主要介紹了C++虛函數表和虛析構,虛函數表是C++實現多態(tài)的基礎,多態(tài)是面向對象的三大特性之一,下面文章我們一起來看看詳細內容,需要的朋友可以參考一下

1、虛函數表

虛函數表是C++實現多態(tài)的基礎,多態(tài)是面向對象的三大特性之一,多態(tài)有利于提高代碼的可讀性,便于后期代碼的擴展和維護。我們都知道多態(tài)的實現是基于虛函數表,那么虛函數表是什么時候創(chuàng)建的呢?虛函數表是怎么實現多態(tài)的功能的呢?

首先應該明確多態(tài)也稱為動態(tài)多態(tài),他是在程序運行時候確定函數地址的,也就是程序在運行時,如果類成員函數加了virtual關鍵字,就會建立一個虛函數指針(vfptr)指針指向一個虛函數表,這個虛函數表就保存了虛函數的地址,子類繼承父類也自然繼承了虛函數指針,當子類重寫父類的虛函數時,虛函數指針所指向的虛函數表中的虛函數地址就會被覆蓋,替換成子類的虛函數地址。也就是通過父類的虛函數指針找到了子類的虛函數地址,進而執(zhí)行這個函數。

下面我們通過代碼進行詳細說明:

#include <iostream>
using namespace std;

class Base{
public:
    void func(){
        cout << "Base func" << endl;
    }
};

class Son: public Base{
    void func(){
        cout << "Son func" << endl;
    }
};

void test(Base& base) {
    base.func();
}
int main () {
    Son son;

    cout << "sizeof(Base) = " << sizeof(Base) << endl;
    cout << "sizeof(Son)  = " << sizeof(Son) << endl;   
    test(son);
    system("pause");
    return 0;

}

代碼運行結果為:

 因為函數成員不占用類的大小,所以對Base類和Son類輸出大小,都是一個字節(jié),這一個字節(jié)是為了可以實例化類,通過引用基類引用派生類,調用func函數,函數調用了基類的func,那么如果我們加上virtual關鍵字后,就不是這種情況了。

#include <iostream>
using namespace std;

class Base{
public:
    virtual void func(){
        cout << "Base func" << endl;
    }
};

class Son: public Base{
    void func(){
        cout << "Son func" << endl;
    }
};


void test(Base& base) {
    base.func();
}
int main () {
    Son son;

    cout << "sizeof(Base) = " << sizeof(Base) << endl;
    cout << "sizeof(Son)  = " << sizeof(Son) << endl;   
    test(son);
    system("pause");
    return 0;

}

代碼運行結果為:

 可以看到加了virtual關鍵字后,父類和子類的大小都變成了四字節(jié),這是因為生成了虛函數指針,指針指向虛函數表,虛函數表存儲了虛函數地址,繼承了父類的子類重寫了虛函數,虛函數表中的函數地址被替換,再次調用虛函數就是調用了子類的函數func。

2、虛析構

虛析構主要是為了解決子類中有屬性開辟到堆區(qū),父類指針調用函數時,無法調用到子類的析構代碼,導致子類堆區(qū)內存無法釋放。

首先我們看一下子類堆區(qū)內存開辟,通過父類指針來調用函數,捕捉他們的構造函數和析構函數看下運行結果:

#include <iostream>
using namespace std;

class Base{
public:
    Base(){
        cout << "Base 的構造函數調用" << endl;
    }

    ~Base(){
        cout << "Base 的析構函數調用" << endl;
    }
    virtual void func(){
        cout << "Base func" << endl;
    }
};

class Son: public Base{
public:
    Son(int val):m_val(new int (val)) {
        cout << "Son 的構造函數調用" << endl;
    }

    ~Son(){
        cout << "Son 的析構函數調用" << endl;
        if (m_val != NULL) {
            
            delete m_val;
            cout << "Son 析構函數的堆內存釋放" << endl;
            m_val = NULL;
        }
    }
    void func(){
        cout << "Son func" << endl;
    }

    void funcTest(){
        cout << "funcTest 函數調用" << endl;
    }

    int* m_val = NULL;
};


void test() {
   
    Base *base = new Son(10);
    base->func();
    //base->funcTest(); //無法調用,因為虛函數表中不能找到這個函數的地址
    delete base;
    base = NULL;
}


int main () {
    test();    
    system("pause");
    return 0;

}

代碼運行結果為:

 可以明確,通過父類指針來調用函數的時候,無法調用Son類的析構函數,在Son類在堆區(qū)上申請的內存就無法釋放,造成內存泄漏。Son類的析構函數不能調用的主要原因就是在虛函數表中找不到Son的析構函數地址,解決辦法就是把Base類的寫成虛析構函數或者純虛析構函數,

下面給出Base類為純虛析構函數的代碼和運行結果:

#include <iostream>
using namespace std;

class Base{
public:
    Base(){
        cout << "Base 的構造函數調用" << endl;
    }
    virtual ~Base() = 0;

    virtual void func(){
        cout << "Base func" << endl;
    }
};
    Base :: ~Base(){
        cout << "Base 的析構函數調用" << endl;
    }

class Son: public Base{
public:
    Son(int val):m_val(new int (val)) {
        cout << "Son 的構造函數調用" << endl;
    }

    ~Son(){
        cout << "Son 的析構函數調用" << endl;
        if (m_val != NULL) {
            
            delete m_val;
            cout << "Son 析構函數的堆內存釋放" << endl;
            m_val = NULL;
        }
    }
    void func(){
        cout << "Son func" << endl;
    }

    void funcTest(){
        cout << "funcTest 函數調用" << endl;
    }

    int* m_val = NULL;
};


void test() {
   
    Base *base = new Son(10);
    base->func();
    //base->funcTest(); //無法調用,因為虛函數表中不能找到這個函數的地址
    delete base;
    base = NULL;
}


int main () {
    test();    
    system("pause");
    return 0;

}

代碼運行結果為:

 可以看到只要把Base類的析構函數寫成虛析構函數或純虛析構函數,通過父類指針調用函數,子類的析構代碼會被調用,子類堆區(qū)內存得到釋放。

到此這篇關于C++虛函數表和虛析構介紹的文章就介紹到這了,更多相關C++虛函數表和虛析構內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • OPENCV批量讀取圖片實現方法

    OPENCV批量讀取圖片實現方法

    下面小編就為大家?guī)硪黄狾PENCV批量讀取圖片實現方法。小編覺得挺不錯的?,F在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • C語言中傳值與傳指針的介紹與區(qū)別

    C語言中傳值與傳指針的介紹與區(qū)別

    這篇文章主要給大家介紹了關于C語言中傳值與傳指針的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用C語言具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-06-06
  • c++?error:crosses?initialization?of問題解決分析

    c++?error:crosses?initialization?of問題解決分析

    這篇文章主要介紹了c++?error:crosses?initialization?ofde?問題解決分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • OpenGL繪制三次Bezier曲線

    OpenGL繪制三次Bezier曲線

    這篇文章主要為大家詳細介紹了OpenGL繪制三次Bezier曲線,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • Qt qml實現動態(tài)輪播圖效果

    Qt qml實現動態(tài)輪播圖效果

    這篇文章主要為大家詳細介紹了Qt和qml實現動態(tài)輪播圖效果的相關知識,文中的示例代碼講解詳細,具有一定的借鑒價值,有需要的小伙伴可以參考一下
    2024-12-12
  • C++中Semaphore內核對象用法實例

    C++中Semaphore內核對象用法實例

    這篇文章主要介紹了C++中Semaphore內核對象用法實例,有助于深入了解信號量(Semaphore)的基本用法,需要的朋友可以參考下
    2014-10-10
  • C++使用redis的實例詳解

    C++使用redis的實例詳解

    這篇文章主要介紹了C++使用redis的實例詳解的相關資料,希望通過本文能幫助到大家,讓大家理解掌握這部分內容,需要的朋友可以參考下
    2017-10-10
  • CLion搭建配置C++開發(fā)環(huán)境的圖文教程 (MinGW-W64 GCC-8.1.0)

    CLion搭建配置C++開發(fā)環(huán)境的圖文教程 (MinGW-W64 GCC-8.1.0)

    這篇文章主要介紹了CLion搭建配置C++開發(fā)環(huán)境的教程 (MinGW-W64 GCC-8.1.0),本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-02-02
  • C++ 虛函數專題

    C++ 虛函數專題

    這篇文章主要介紹了C++中虛函數的知識點,文中配合代碼講解非常細致,供大家參考和學習,感興趣的朋友可以了解下
    2020-06-06
  • 數據結構之歸并排序的實例詳解

    數據結構之歸并排序的實例詳解

    這篇文章主要介紹了數據結構之歸并排序的實例詳解的相關資料,這里對歸并排序進行詳細介紹,需要的朋友可以參考下
    2017-08-08

最新評論