欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

【C++】菱形繼承與虛擬菱形繼承的對(duì)比分析

    在繼承中經(jīng)常會(huì)遇到這種情況:有一個(gè)超類(lèi)A,子類(lèi)B1,B2繼承了A,而類(lèi)D又繼承了父類(lèi)B1,B2。在這種情況下如果按照我們以前的正常的菱形繼承的話(huà)會(huì)有一個(gè)問(wèn)題是子類(lèi)C會(huì)繼承兩次超類(lèi)A中的成員,當(dāng)在C中想訪(fǎng)問(wèn)繼承來(lái)自B1,B2中A的元素會(huì)出現(xiàn)兩個(gè)問(wèn)題:

創(chuàng)新互聯(lián)建站基于成都重慶香港及美國(guó)等地區(qū)分布式IDC機(jī)房數(shù)據(jù)中心構(gòu)建的電信大帶寬,聯(lián)通大帶寬,移動(dòng)大帶寬,多線(xiàn)BGP大帶寬租用,是為眾多客戶(hù)提供專(zhuān)業(yè)服務(wù)器托管報(bào)價(jià),主機(jī)托管價(jià)格性?xún)r(jià)比高,為金融證券行業(yè)IDC機(jī)房托管,ai人工智能服務(wù)器托管提供bgp線(xiàn)路100M獨(dú)享,G口帶寬及機(jī)柜租用的專(zhuān)業(yè)成都idc公司。

    問(wèn)題一、數(shù)據(jù)的冗余

    問(wèn)題二、訪(fǎng)問(wèn)的二意性

出現(xiàn)了這種問(wèn)題那么我們?cè)撊绾谓鉀Q呢?

    C++中為了解決這個(gè)問(wèn)題引入了虛擬菱形繼承,那么虛擬菱形繼承是怎么解決的呢?

首先給大家先畫(huà)兩個(gè)圖比較下菱形繼承和虛擬菱形繼承在繼承時(shí)在內(nèi)存中的成員分布情況:

   一、 菱形繼承:

沒(méi)有繼承以前的超類(lèi)A和父類(lèi)B1,B2;

【C++】菱形繼承與虛擬菱形繼承的對(duì)比分析

繼承超類(lèi)A以后的B1,B2;

【C++】菱形繼承與虛擬菱形繼承的對(duì)比分析

子類(lèi)D繼承B1,B2以后的內(nèi)存分布情況

【C++】菱形繼承與虛擬菱形繼承的對(duì)比分析

    通過(guò)圖我們可以看出菱形繼承存在很多的數(shù)據(jù)冗余,如超類(lèi)A的成員ia,ca都有兩份,訪(fǎng)問(wèn)時(shí)也會(huì)出先二義性的錯(cuò)誤。

    二、虛擬菱形繼承

沒(méi)有繼承以前的超類(lèi)A和父類(lèi)B1,B2;

【C++】菱形繼承與虛擬菱形繼承的對(duì)比分析

虛擬繼承超類(lèi)A以后的B1,B2;

【C++】菱形繼承與虛擬菱形繼承的對(duì)比分析

虛擬繼承B1,B2后的D;

【C++】菱形繼承與虛擬菱形繼承的對(duì)比分析

看完分布圖以后,我們看下代碼和D在內(nèi)存中的分布

#include<iostream>
using namespace std;

class A
{
public:
    int ia;
    char ca;
public:
    A()
    :ia(0)
    , ca('A')
    {}

    virtual void f()
    {
        cout << "A::f()" << endl;
    }

    virtual void Bf()
    {
        cout << "A::Af()" << endl;
    }
};

class B1:virtual public A
{
public:
    int ib1;
    char cb1;
public:
    B1()
    :ib1(1)
    , cb1('1')
    {}
    virtual void f()
    {
        cout << "B1::f()" << endl;
    }

    virtual void f1()
    {
        cout << "B1::f1()" << endl;
    }

    virtual void B1f()
    {
        cout << "B1::B1f()" << endl;
    }

};

class B2:virtual public A
{
public:
    int ib2;
    char cb2;
public:
    B2()
    :ib2(2)
    , cb2('2')
    {}

    virtual void f()
    {
        cout << "B2::f()" << endl;
    }

    virtual void f2()
    {
        cout << "B2::f2()" << endl;
    }

    virtual void B2f()
    {
        cout << "B2::B2f()" << endl;
    }

};

class D :public B1,public B2
{
public:
    int id;
    char cd;
public:
    D()
        :id(3)
        , cd('D')
    {}

    virtual void f()
    {
        cout << "D::f()" << endl;
    }

    virtual void f1()
    {
        cout << "D::f1()" << endl;
    }

    virtual void f2()
    {
        cout << "D::f2()" << endl;
    }

    virtual void Df()
    {
        cout << "D::Df()" << endl;
    }

};

typedef void(*Fun)();
void PrintVTable(int* VTable)
{
    cout << " 虛表地址>" << VTable << endl;

    for (int i = 0; VTable[i] != 0; ++i)
    {
        printf(" 第%d個(gè)虛函數(shù)地址 :0X%x,->", i, VTable[i]);
        Fun f = (Fun)VTable[i];
        f();
    }
}



void test()
{
    A a;
    B1 b1;
    B2 b2;
    D d1;

    cout << "sizeof(A)::" << sizeof(a) << endl;
    cout << "sizeof(B1)::" << sizeof(b1) << endl;
    cout << "sizeof(B2)::" << sizeof(b2) << endl;
    cout << "sizeof(D)::" << sizeof(d1) << endl;

    int* VTable = (int*)(*(int*)&d1);
    PrintVTable(VTable);
    cout << "        虛基表指針->: " << (int*)((int*)&d1 + 1) << endl;
    cout << "         B1::ib1 = " << *(int*)((int*)&d1 + 2) << endl;
    cout << "         B1::cb1 =" << (char)*((int*)&d1 + 3) << endl;

    VTable = (int*)*((int*)&d1 + 4);
    PrintVTable(VTable);
    cout << "        虛基表指針->:" << (int*)((int*)&d1 + 5) << endl;
    cout << "         B2::ib2 =" << *(int*)((int*)&d1 + 6) << endl;
    cout << "         B2::cb2 =" << (char)*((int*)&d1 + 7) << endl;

    cout << "         D::ID =" << *((int*)&d1 + 8) << endl;
    cout << "         D::cd =" << (char)*((int*)&d1 + 9) << endl;
    cout << " 虛基表的偏移地址->:"<<(int*)((int*)&d1 + 10) << endl;
    VTable = (int*)*((int*)&d1 + 11);
    PrintVTable(VTable);
    cout << "         A::ia =" << *(int*)((int*)&d1 + 12) << endl;
    cout << "         A::ca =" << (char)*((int*)&d1 + 13) << endl;
    
}

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

一、父類(lèi)b1的內(nèi)存分布情況

【C++】菱形繼承與虛擬菱形繼承的對(duì)比分析

二、父類(lèi)b2的內(nèi)存分布情況

【C++】菱形繼承與虛擬菱形繼承的對(duì)比分析

三、子類(lèi)d1的內(nèi)存分布情況

【C++】菱形繼承與虛擬菱形繼承的對(duì)比分析

這些都跟前面畫(huà)圖分析的一樣。我們?cè)倏匆幌旅總€(gè)類(lèi)的大小:

【C++】菱形繼承與虛擬菱形繼承的對(duì)比分析

將菱形繼承與虛擬菱形繼承做比較:

【C++】菱形繼承與虛擬菱形繼承的對(duì)比分析

  按照正常情況下:在菱形繼承與虛擬菱形繼承時(shí),超類(lèi)大小一樣,但從父類(lèi)開(kāi)始大小發(fā)生區(qū)別,父類(lèi)多了12個(gè)字節(jié),子類(lèi)多了8個(gè)字節(jié)。

  由于要想消除二義性與冗余性,就得將B1、B2中的A部分變?yōu)橐环荩侵荒軐1、B2中A中共同的部分變?yōu)橹羔樦赶駼ase部分。為什么會(huì)這樣呢?

  一、對(duì)于父類(lèi)B1、B2來(lái)說(shuō)因?yàn)槎喈a(chǎn)生了三個(gè)指針,前圖中沒(méi)畫(huà)出來(lái),可以參照子類(lèi)D的圖,通過(guò)虛擬繼承,多增加了一個(gè)虛基表指針,一個(gè)虛基表的偏移地址,另外還繼承了A的虛表,作用是指向一個(gè)地址,地址中保存著父類(lèi)增加的指針的地址與超類(lèi)的地址偏移值,通過(guò)地址與偏移值相加,找到超類(lèi)成員部分,并且兩個(gè)父類(lèi)指針都指向的是同一塊空間。所以多了12個(gè)字節(jié)。

  二、同理,對(duì)于子類(lèi)D來(lái)說(shuō)在同時(shí)多了這些東西的同時(shí)減去重復(fù)繼承的超類(lèi)的成員最后就只是多了8字節(jié)

  通過(guò)這種處理子類(lèi)中父類(lèi)與超類(lèi)公共部分都是同一塊存儲(chǔ)空間,就可以解決菱形繼承的二義性與數(shù)據(jù)冗余問(wèn)題了。

分享名稱(chēng):【C++】菱形繼承與虛擬菱形繼承的對(duì)比分析
文章起源:http://www.chinadenli.net/article46/ieoshg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供關(guān)鍵詞優(yōu)化微信公眾號(hào)企業(yè)建站企業(yè)網(wǎng)站制作建站公司App開(kāi)發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都網(wǎng)頁(yè)設(shè)計(jì)公司