溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

C++語言學(xué)習(xí)(十三)——C++對(duì)象模型分析

發(fā)布時(shí)間:2020-07-16 12:57:07 來源:網(wǎng)絡(luò) 閱讀:764 作者:天山老妖S 欄目:編程語言

C++語言學(xué)習(xí)(十三)——C++對(duì)象模型分析

一、C++對(duì)象模型分析

1、類對(duì)象模型的內(nèi)存布局

class是一種特殊的struct,class與struct遵循相同的內(nèi)存對(duì)齊原則,class中的成員函數(shù)與成員變量是分開存放的,每個(gè)對(duì)象擁有獨(dú)立的成員變量,所有的對(duì)象共享類中的成員函數(shù)。
運(yùn)行時(shí),類對(duì)象退化為結(jié)構(gòu)體的形式:
A、所有成員變量在內(nèi)存中依次排布
B、由于內(nèi)存對(duì)齊的存在,成員變量間可能存在內(nèi)存間隙
C、可以通過內(nèi)存地址訪問成員變量
D、訪問權(quán)限關(guān)鍵字在運(yùn)行時(shí)失效

#include <iostream>

using namespace std;

class A
{
    int i;
    int j;
    char c;
    double d;
public:
    void print()
    {
        cout << "i = " << i << ", "
             << "j = " << j << ", "
             << "c = " << c << ", "
             << "d = " << d << endl;
    }
};

struct B
{
    int i;
    int j;
    char c;
    double d;
};

int main(int argc, char *argv[])
{
    A a;
    //64 bit machine
    cout << "sizeof(A) = " << sizeof(A) << endl;    // 24
    cout << "sizeof(a) = " << sizeof(a) << endl;    // 24
    cout << "sizeof(B) = " << sizeof(B) << endl;    // 24

    a.print();

    B* p = reinterpret_cast<B*>(&a);

    p->i = 1;
    p->j = 2;
    p->c = 'c';
    p->d = 3.14;
    a.print();

    return 0;
}

上述代碼中,class A對(duì)象與struct B對(duì)象在內(nèi)存中的排布相同。

2、派生類類對(duì)象模型

子類是由父類成員疊加子類成員得到的。

#include <iostream>

using namespace std;

class Parent
{
protected:
    int m_i;
    int m_j;
};

class Child : public Parent
{
public:
    Child(int i, int j, double d)
    {
        m_i = i;
        m_j = j;
        m_d = d;
    }
    void print()
    {
        cout << "m_i = "<< m_i << endl;
        cout << "m_j = "<< m_j << endl;
        cout << "m_d = "<< m_d << endl;
    }
private:
    double m_d;
};

struct Test
{
    int i;
    int j;
    double d;
};

int main(int argc, char *argv[])
{
    cout << sizeof(Parent) << endl;//8
    cout << sizeof(Child) << endl;//16
    Child child(1,2,3.14);
    child.print();
    Test* test = reinterpret_cast<Test*>(&child);
    cout << "i = " << test->i << endl;
    cout << "j = " << test->j << endl;
    cout << "d = " << test->d << endl;

    test->i = 100;
    test->j = 200;
    test->d = 3.1415;
    child.print();
    return 0;
}

二、C++多態(tài)的實(shí)現(xiàn)機(jī)制

1、C++多態(tài)的實(shí)現(xiàn)簡介

當(dāng)類中聲明虛函數(shù)時(shí),C++編譯器會(huì)在類中生成一個(gè)虛函數(shù)表。虛函數(shù)表是一個(gè)用于存儲(chǔ)virtual成員函數(shù)地址的數(shù)據(jù)結(jié)構(gòu)。虛函數(shù)表由編譯器自動(dòng)生成與維護(hù),virtual成員函數(shù)會(huì)被編譯器放入虛函數(shù)表中。存在虛函數(shù)時(shí),每個(gè)對(duì)象中都有一個(gè)指向類的虛函數(shù)表的指針。
由于對(duì)象調(diào)用虛函數(shù)時(shí)會(huì)查詢虛函數(shù)表,因此虛函數(shù)的調(diào)用效率比普通成員函數(shù)低。
當(dāng)創(chuàng)建類對(duì)象時(shí),如果類中存在虛函數(shù),編譯器會(huì)在類對(duì)象中增加一個(gè)指向虛函數(shù)表的指針。父類對(duì)象中虛函數(shù)表存儲(chǔ)的是父類的虛函數(shù),子類對(duì)象中虛函數(shù)表存儲(chǔ)的是子類對(duì)象的虛函數(shù)。虛函數(shù)表指針存儲(chǔ)在類對(duì)象存儲(chǔ)空間的開始的前4(8)個(gè)字節(jié)。

2、虛函數(shù)表

如果一個(gè)類包含虛函數(shù),其類包含一個(gè)虛函數(shù)表。
如果一個(gè)基類包含虛函數(shù),基類會(huì)包含一個(gè)虛函數(shù)表,其派生類也會(huì)包含一個(gè)自己的虛函數(shù)表。
虛函數(shù)表是一個(gè)函數(shù)指針數(shù)組,其數(shù)組元素是虛函數(shù)的函數(shù)指針,每個(gè)元素對(duì)應(yīng)一個(gè)虛函數(shù)的函數(shù)指針。非虛成員函數(shù)的調(diào)用并不需要經(jīng)過虛函數(shù)表,所以虛函數(shù)表的元素并不包括非虛成員函數(shù)的函數(shù)指針。?
虛函數(shù)表中虛函數(shù)指針的賦值發(fā)生在編譯器的編譯階段,即在代碼編譯階段虛函數(shù)表就生成。

#include <iostream>

using namespace std;

class Parent
{
public:
    Parent(int i, int j)
    {
        m_i = i;
        m_j = j;
    }
    virtual void print()
    {
        cout << "Parent::" << __func__<< endl;
        cout << "m_i = "<< m_i << endl;
        cout << "m_j = "<< m_j << endl;
    }
    virtual double sum()
    {
        cout << "Parent::" << __func__<< endl;
        double ret = m_i + m_j;
        cout <<ret << endl;
        return ret;
    }
    virtual void display()
    {
        cout << "Parent::display()" << endl;
    }
protected:
    int m_i;
    int m_j;
};

class Child : public Parent
{
public:
    Child(int i, int j, double d):Parent(i, j)
    {
        m_d = d;
    }
    virtual void print()
    {
        cout << "Child::" << __func__<< endl;
        cout << "m_i = "<< m_i << endl;
        cout << "m_j = "<< m_j << endl;
        cout << "m_d = "<< m_d << endl;
    }
    virtual double sum()
    {
        cout << "Child::" << __func__<< endl;
        double ret = m_i + m_j + m_d;
        cout << ret << endl;
        return ret;
    }
private:
    void display()
    {
        cout << "Child::display()" << endl;
    }
private:
    double m_d;
};

struct Test
{
    void* vptr;
    int i;
    int j;
    double d;
};

int main(int argc, char *argv[])
{
    cout << sizeof(Parent) << endl;//12
    cout << sizeof(Child) << endl;//24
    Child child(1,2,3.14);
    Test* test = reinterpret_cast<Test*>(&child);
    cout << "virtual Function Table Pointer:" << endl;
    cout << "vptr = " << test->vptr << endl;
    //虛函數(shù)表指針位于類對(duì)象的前4字節(jié)
    cout << "child Object address: " << &child << endl;
    cout << "Member Variables Address: " << endl;
    cout << "&vptr = " << &test->vptr << endl;
    cout << "&i = " << &test->i << endl;
    cout << "&j = " << &test->j << endl;
    cout << "&d = " << &test->d << endl;

    //函數(shù)指針方式訪問類的虛函數(shù)
    cout << "Virtual Function Table: " << endl;
    cout << "Virtual print Function Address: " << endl;
    cout << (long*)(*((long *)(*((long *)&child)) + 0)) <<endl;
    cout << "Virtual sum Function Address: " << endl;
    cout << (long*)(*((long *)(*((long *)&child)) + 1)) <<endl;
    cout << "Virtual display Function Address: " << endl;
    cout << (long*)(*((long *)(*((long *)&child)) + 2)) <<endl;
    typedef void (*pPrint)();
    pPrint print = (pPrint)(*((long *)(*((long *)&child)) + 0));
    print();

    typedef double (*pSum)(void);
    pSum sum = (pSum)(*((long *)(*((long *)&child)) + 1));
    sum();

    typedef void (*pDisplay)(void);
    pDisplay display = (pDisplay)(*((long *)(*((long *)&child)) + 2));
    display();
    return 0;
}

上述代碼中,通過類對(duì)象的虛函數(shù)表指針可以訪問類的虛函數(shù)表,虛函數(shù)表順序存儲(chǔ)了類的虛函數(shù)的函數(shù)地址,通過函數(shù)指針的方式可以調(diào)用類的虛函數(shù),包括聲明為private的虛函數(shù)。但由于使用函數(shù)指針方式訪問類的虛函數(shù)時(shí),類的虛函數(shù)在執(zhí)行過程中其this指針指向的對(duì)象是不確定的,因此訪問到的類對(duì)象的成員變量的值是垃圾值。

3、虛函數(shù)表指針

虛函數(shù)表屬于類,而不是屬于某個(gè)具體的類對(duì)象,一個(gè)類只需要一個(gè)虛函數(shù)表。同一個(gè)類的所有對(duì)象都使用類的唯一虛函數(shù)表。?為了指定類對(duì)象的虛函數(shù)表,類對(duì)象內(nèi)部包含一個(gè)指向虛函數(shù)表的指針,指向類的虛函數(shù)表。為了讓每個(gè)類對(duì)象都擁有一個(gè)虛函數(shù)表指針,編譯器在類中添加了一個(gè)指針*__vptr,用來指向虛函數(shù)表。當(dāng)類對(duì)象在創(chuàng)建時(shí)便擁有__vptr指針,且__vptr指針的值會(huì)自動(dòng)被設(shè)置為指向類的虛函數(shù)表。

class Parent
{
public:
    Parent(int i, int j)
    {
        m_i = i;
        m_j = j;
    }
    virtual void print()
    {
        cout << "Parent::" << __func__<< endl;
        cout << "m_i = "<< m_i << endl;
        cout << "m_j = "<< m_j << endl;
    }
    virtual double sum()
    {
        cout << "Parent::" << __func__<< endl;
        double ret = m_i + m_j;
        cout <<ret << endl;
        return ret;
    }
    virtual void display()
    {
        cout << "Parent::display()" << endl;
    }
    int add(int value)
    {
        return m_i + m_j + value;
    }
protected:
    void func()
    {

    }
protected:
    int m_i;
    int m_j;
};

上述代碼中,類的虛函數(shù)表如下:
類Parent對(duì)象的內(nèi)存布局中,虛函數(shù)表指針位于類對(duì)象存儲(chǔ)空間的開頭,其值0X409004是類Parent的虛函數(shù)表的首地址,虛函數(shù)表中的第一個(gè)數(shù)組元素是虛函數(shù)Parent::print的地址,第二個(gè)數(shù)組元素是虛函數(shù)Parent::sum,第三個(gè)數(shù)組元素是虛函數(shù)Parent::display,非虛函數(shù)不在虛函數(shù)表中。
C++語言學(xué)習(xí)(十三)——C++對(duì)象模型分析

4、類對(duì)象的內(nèi)存布局

對(duì)于含有虛函數(shù)的類,虛函數(shù)表指針位于類對(duì)象內(nèi)存布局的開始位置,然后依次排列類繼承自父類的成員變量,最后依次排列類自身的非靜態(tài)成員變量。

#include <iostream>

using namespace std;

class Parent
{
public:
    Parent(int i, int j)
    {
        m_i = i;
        m_j = j;
    }
    virtual void print()
    {
        cout << "Parent::" << __func__<< endl;
        cout << "m_i = "<< m_i << endl;
        cout << "m_j = "<< m_j << endl;
    }
    virtual double sum()
    {
        cout << "Parent::" << __func__<< endl;
        double ret = m_i + m_j;
        cout <<ret << endl;
        return ret;
    }
    virtual void display()
    {
        cout << "Parent::display()" << endl;
    }
    int add(int value)
    {
        return m_i + m_j + value;
    }
protected:
    void func()
    {

    }
protected:
    int m_i;
    int m_j;
    static int m_count;
};
int Parent::m_count  = 0;

class ChildA : public Parent
{
public:
    ChildA(int i, int j, double d):Parent(i, j)
    {
        m_d = d;
    }
    virtual void print()
    {
        cout << "ChildA::" << __func__<< endl;
        cout << "m_i = "<< m_i << endl;
        cout << "m_j = "<< m_j << endl;
        cout << "m_d = "<< m_d << endl;
    }
    virtual double sum()
    {
        cout << "ChildA::" << __func__<< endl;
        double ret = m_i + m_j + m_d;
        cout << ret << endl;
        return ret;
    }
private:
    void display()
    {
        cout << "ChildA::display()" << endl;
    }
private:
    double m_d;
};

class ChildB : public Parent
{
public:
    ChildB(int i, int j, double d):Parent(i, j)
    {
        m_d = d;
    }
    virtual void print()
    {
        cout << "ChildB::" << __func__<< endl;
        cout << "m_i = "<< m_i << endl;
        cout << "m_j = "<< m_j << endl;
        cout << "m_d = "<< m_d << endl;
    }
    virtual double sum()
    {
        cout << "ChildB::" << __func__<< endl;
        double ret = m_i + m_j + m_d;
        cout << ret << endl;
        return ret;
    }
private:
    void display()
    {
        cout << "ChildB::display()" << endl;
    }
private:
    double m_d;
};

struct ParentTest
{
    void* vptr;
    int i;
    int j;
};

struct ChildTest
{
    void* vptr;
    int i;
    int j;
    double d;
};

int main(int argc, char *argv[])
{
    cout << sizeof(Parent) << endl;//12
    cout << sizeof(ChildA) << endl;//24
    cout << endl;
    cout << "Parent..." <<endl;
    Parent parent(1,2);
    ParentTest* parenttest = reinterpret_cast<ParentTest*>(&parent);
    cout << "Member Variable Value:"<< endl;
    //虛函數(shù)表的首地址
    cout << parenttest->vptr << endl;//編譯時(shí)確定
    cout << parenttest->i << endl;//1
    cout << parenttest->j << endl;//2
    cout << "Member Variable Address:" << endl;
    cout << &parenttest->vptr << endl;
    cout << &parenttest->i << endl;
    cout << &parenttest->j << endl;
    cout << endl;
    cout << "Child..." << endl;
    ChildA child(1,2,3.14);
    ChildTest* childtest = reinterpret_cast<ChildTest*>(&child);
    cout << "Member Variable Value:"<< endl;
    //虛函數(shù)表的首地址
    cout << childtest->vptr << endl;//編譯時(shí)確定
    cout << childtest->i << endl;//1
    cout << childtest->j << endl;//2
    cout << childtest->d << endl;//3.14
    cout << "Member Variable Address:" << endl;
    cout << &childtest->vptr << endl;
    cout << &childtest->i << endl;
    cout << &childtest->j << endl;
    cout << &childtest->d << endl;

    return 0;
}

C++語言學(xué)習(xí)(十三)——C++對(duì)象模型分析

5、動(dòng)態(tài)綁定的實(shí)現(xiàn)

Parent、ChildA、ChildB三個(gè)類都有虛函數(shù),C++編譯器編譯時(shí)會(huì)為每個(gè)類都創(chuàng)建一個(gè)虛函數(shù)表,即類Parent的虛函數(shù)表(Parent vtbl),類ChildA的虛函數(shù)表(ChildA vtbl),類ChildB的虛表(ChildB vtbl)。類Parent、ChildA、ChildB的對(duì)象都擁有一個(gè)虛函數(shù)表指針*vptr,用來指向自己所屬類的虛函數(shù)表。?
類Parent包括三個(gè)虛函數(shù),Parent類的虛函數(shù)表包含三個(gè)指針,分別指向Parent::print()、Parent::sum()、Parent::display()三個(gè)虛函數(shù)函數(shù)。?
類ChildA繼承于類Parent,因此類ChildA可以調(diào)用父類Parent的函數(shù),但類ChildA重寫Parent::print()、Parent::sum()、Parent::display()三個(gè)虛函數(shù),因此類ChildA 虛函數(shù)表的三個(gè)函數(shù)指針分別指向ChildA::print()、ChildA::sum()、ChildA::display()。?
類ChildB繼承于類Parent,因此類ChildB可以調(diào)用類Parent的函數(shù),但由于類ChildB重寫Parent::print()、Parent::sum()函數(shù),類ChildB虛函數(shù)表有三個(gè)函數(shù)指針,第一個(gè)函數(shù)指針指向Parent::display()虛函數(shù),第二個(gè)第三個(gè)依次指向ChildB::print()、ChildB::sum()虛函數(shù)。?

ChildA childA;
Parent* p = &childA;

當(dāng)定義一個(gè)ChildA類的對(duì)象childA時(shí),childA對(duì)象包含一個(gè)虛函數(shù)表指針,指向ChildA類的虛函數(shù)表。
當(dāng)定義一個(gè)Parent類的指針p指向childA對(duì)象時(shí),p指針只能指向ChildA對(duì)象的父類Parent部分,但由于虛函數(shù)表指針位于對(duì)象存儲(chǔ)空間的開始,因此p指針可以訪問childA對(duì)象的虛函數(shù)表指針。由于childA對(duì)象的虛函數(shù)表指針指向ChildA類的虛函數(shù)表,因此p指針可以訪問類ChildA的虛函數(shù)表。
當(dāng)使用指針調(diào)用print函數(shù),程序在執(zhí)行p->print()時(shí),會(huì)發(fā)現(xiàn)p是個(gè)指針,且調(diào)用的函數(shù)是虛函數(shù)。?
首先,根據(jù)虛函數(shù)表指針p->vptr來訪問對(duì)象childA對(duì)應(yīng)的虛函數(shù)表。
然后,在虛函數(shù)表中查找所調(diào)用的虛函數(shù)對(duì)應(yīng)的條目。由于虛函數(shù)表在編譯階段就生成,所以可以根據(jù)所調(diào)用的函數(shù)定位到虛函數(shù)表中的對(duì)應(yīng)條目。對(duì)于 p->print()的調(diào)用,類ChildA虛函數(shù)表的第一項(xiàng)即是print函數(shù)指針對(duì)應(yīng)的條目。?
最后,根據(jù)虛函數(shù)表中找到的函數(shù)指針,調(diào)用函數(shù)ChildA::print()。

Parent base;
Parent* p = &base;
p->print();

當(dāng)base對(duì)象在創(chuàng)建時(shí),base對(duì)象的虛函數(shù)表指針vptr已設(shè)置為指向Parent類的虛函數(shù)表,p->vptr指向Parent虛函數(shù)表。print在Parent虛函數(shù)表中相應(yīng)的條目指向Parent::print()函數(shù),所以 p->print()會(huì)調(diào)用Parent::print()函數(shù)。
虛函數(shù)的調(diào)用的三個(gè)步驟用表達(dá)式(*(p->vptr)[n])(p)可以概括。

6、函數(shù)指針實(shí)現(xiàn)多態(tài)

#include <iostream>

using namespace std;

typedef void (*vfunc)();

class Parent
{
public:
    vfunc print;
    Parent()
    {
        print = Parent::display;
    }
    static void display()
    {
        cout << "Parent::" << __func__<< endl;
    }
};

class Child : public Parent
{
public:
    Child()
    {
        print = Child::display;
    }
    static void display()
    {
        cout << "Child::" << __func__<< endl;

    }
};

int main(int argc, char *argv[])
{
    Parent parent;
    parent.print();
    Child child;
    child.print();
    Parent* p = &child;
    p->print();

    return 0;
}

// output:
// Parent::display
// Child::display
// Child::display

上述代碼使用函數(shù)指針實(shí)現(xiàn)了多態(tài),繞過了虛函數(shù)表,避免了虛函數(shù)表的性能損失。

三、虛函數(shù)經(jīng)典問題

1、構(gòu)造函數(shù)不能為虛函數(shù)

由于在構(gòu)造函數(shù)執(zhí)行完后,類對(duì)象的虛函數(shù)表指針才被正確初始化。因此構(gòu)造函數(shù)不能為虛函數(shù)。類對(duì)象中的虛函數(shù)表指針是在調(diào)用構(gòu)造函數(shù)的時(shí)候完成初始化的。因此,在構(gòu)造函數(shù)調(diào)用前,虛函數(shù)表指針還沒有完成初始化,無法調(diào)用虛的構(gòu)造函數(shù)。
在構(gòu)造函數(shù)進(jìn)入函數(shù)體前,進(jìn)行虛函數(shù)表指針的初始化,將虛函數(shù)表指針初始化為當(dāng)前類的虛函數(shù)表地址,即在基類調(diào)用構(gòu)造函數(shù)的時(shí)候,會(huì)把基類的虛函數(shù)表地址賦值給虛函數(shù)表指針,而如果進(jìn)執(zhí)行到子類的構(gòu)造函數(shù)時(shí),把子類的虛函數(shù)表地址賦值給虛函數(shù)表指針。因此,在派生類對(duì)象的構(gòu)造時(shí),虛函數(shù)表指針指向的虛函數(shù)表地址是動(dòng)態(tài)變化的。

#include <iostream>

using namespace std;

class Parent
{
public:
    Parent(int i, int j)
    {
        m_i = i;
        m_j = j;
        cout << "Parent(int i, int j): " << this << endl;
        //虛函數(shù)表指針
        int* vptr = (int*)*((int*)this);
        cout << "vptr: " << vptr << endl;
    }
    virtual void print()
    {
        cout << "Parent::" << __func__<< endl;
        cout << "m_i = "<< m_i << endl;
        cout << "m_j = "<< m_j << endl;
    }
    virtual ~Parent()
    {
        cout << "~Parent(): " << this << endl;
    }
protected:
    int m_i;
    int m_j;
};

class Child : public Parent
{
public:
    Child(int i, int j, double d):Parent(i, j)
    {
        m_d = d;
        cout << "Child(int i, int j, double d): " << this << endl;
        //虛函數(shù)表指針
        int* vptr = (int*)*((int*)this);
        cout << "vptr: " << vptr << endl;
    }
    virtual void print()
    {
        cout << "Child::" << __func__<< endl;
        cout << "m_i = "<< m_i << endl;
        cout << "m_j = "<< m_j << endl;
        cout << "m_d = "<< m_d << endl;
    }
    ~Child()
    {
        cout << "~Child(): " << this <<endl;
    }
private:
    double m_d;
};

int main(int argc, char *argv[])
{
    Parent* p = new Child(1,2,3.14);
    p->print();
    delete p;
    return 0;
}

2、析構(gòu)函數(shù)中可以為虛函數(shù)

析構(gòu)函數(shù)可以為虛函數(shù),可以發(fā)生多態(tài)。工程實(shí)踐中,如果基類中有虛成員函數(shù),建議將析構(gòu)函數(shù)聲明為虛函數(shù),確保對(duì)象銷毀時(shí)觸發(fā)正確的析構(gòu)函數(shù)調(diào)用,保證資源的正確回收。

#include <iostream>

using namespace std;

class Parent
{
public:
    Parent(int i, int j)
    {
        m_i = i;
        m_j = j;
        cout << "Parent(int i, int j)" << endl;
    }
    virtual void print()
    {
        cout << "Parent::" << __func__<< endl;
        cout << "m_i = "<< m_i << endl;
        cout << "m_j = "<< m_j << endl;
    }
    virtual ~Parent()
    {
        cout << "~Parent()" << endl;
    }
protected:
    int m_i;
    int m_j;
};

class Child : public Parent
{
public:
    Child(int i, int j, double d):Parent(i, j)
    {
        m_d = d;
        cout << "Child(int i, int j, double d)" << endl;
    }
    virtual void print()
    {
        cout << "Child::" << __func__<< endl;
        cout << "m_i = "<< m_i << endl;
        cout << "m_j = "<< m_j << endl;
        cout << "m_d = "<< m_d << endl;
    }
    ~Child()
    {
        cout << "~Child()" <<endl;
    }
private:
    double m_d;
};

int main(int argc, char *argv[])
{
    Parent* p = new Child(1,2,3.14);
    p->print();
    delete p;
    return 0;
}

3、構(gòu)造函數(shù)內(nèi)不能發(fā)生多態(tài)行為

在調(diào)用基類的構(gòu)造函數(shù)時(shí),其虛函數(shù)表指針指向的是基類的虛函數(shù)表,而在調(diào)用派生類的構(gòu)造函數(shù)時(shí),其虛函數(shù)表指針指向的是派生類的虛函數(shù)表。因此,構(gòu)造函數(shù)內(nèi)不能發(fā)生多態(tài)行為。

4、析構(gòu)函數(shù)內(nèi)不能發(fā)生多態(tài)行為

在調(diào)用派生類的析構(gòu)函數(shù)時(shí),其虛函數(shù)表指針指向的是派生類的虛函數(shù)表;在調(diào)用基類的析構(gòu)函數(shù)時(shí),其虛函數(shù)表指針指向的是基類的虛函數(shù)表,并且派生類的虛函數(shù)表已經(jīng)被銷毀。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI