亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

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

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

C++中被遺棄的多重繼承是什么

發布時間:2022-01-12 21:40:21 來源:億速云 閱讀:153 作者:iii 欄目:編程語言

本篇內容介紹了“C++中被遺棄的多重繼承是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!

        我們在學習了 C++ 的繼承之后,有沒有想過一個類是否被允許繼承自多個父類呢?那么在 C++ 中是支持編寫多重繼承的代碼的,即一個子類可以擁有多個父類。此時子類擁有所有父類的成員變量,子類繼承所有父類的成員函數,子類對象可以當作任意父類對象來使用。那么多重繼承的語法如下所示,其本質與單繼承相同!

class Derived : public BaseA, public BaseB
{
    // ...
};

        下來我們就以代碼為例來進行分析

#include <iostream>

using namespace std;

class BaseA
{
    int ma;
public:
    BaseA(int a)
    {
        ma = a;
    }
    
    int getA()
    {
        return ma;
    }
};

class BaseB
{
    int mb;
public:
    BaseB(int b)
    {
        mb = b;
    }
    
    int getB()
    {
        return mb;
    }
};

class Derived : public BaseA, public BaseB
{
    int mc;
public:
    Derived(int a, int b, int c) : BaseA(a), BaseB(b)
    {
        mc = c;
    }
    
    int getC()
    {
        return mc;
    }
    
    void print()
    {
        cout << "ma = " << getA() << ", "
             << "mb = " << getB() << ", "
             << "mc = " << mc << endl;
    }
};

int main()
{
    cout << "sizeof(Derived) = " << sizeof(Derived) << endl;
    
    Derived d(1, 2, 3);
    
    d.print();
    
    cout << "d.getA() = " << d.getA() << endl;
    cout << "d.getB() = " << d.getB() << endl;
    cout << "d.getC() = " << d.getC() << endl;
    
    cout << endl;
    
    BaseA* pa = &d;
    BaseB* pb = &d;
    
    cout << "pa->getA() = " << pa->getA() << endl;
    cout << "pb->getB() = " << pb->getB() << endl;
    
    cout << endl;
    
    void* paa = pa;
    void* pbb = pb;
    
    if( paa == pbb )
    {
        cout << "Pointer to the same object!" << endl;
    }
    else
    {
        cout << "Error!" << endl;
    }
/*
    cout << "pa = " << pa << endl;
    cout << "pb = " << pb << endl;
    cout << "paa = " << paa << endl;
    cout << "pbb = " << pbb << endl;
*/    
    return 0;
}

        我們在程序中定義了父類 A 和 B,子類 Derived 繼承自 A 和 B。我們先來打印下子類的內存大小,按照我們之前學習的知識可知,這肯定為 12。接著是定義了一個子類對象 d,通過調用它的 print 成員函數和繼承過來的 get* 函數打印值,看看初始化是否成功。接著是定義了兩個父類類型的指針并將他們指向子類對象 d,再用 void* 指針指向兩個父類指針,按理說它們都指向的是子類對象 d,所以在下面的判斷中,應該是相等的,打印的是 Pointer to the same object! 下來我們編譯看看結果

C++中被遺棄的多重繼承是什么

        我們可以看到之前分析的都是對的,但是最后一個打印的竟然不是我們所期望的。也就是說,它們雖然指向的都是同一個對象的地址,但是地址竟然不相同。我們再來將注釋去掉,看看他們四個的指針究竟是多少?

C++中被遺棄的多重繼承是什么

        我們看到他們打印的地址確實不一樣。這便是多重繼承帶來的問題之一了,通過多重繼承得到的對象可能擁有“不同的地址”!!!其關系圖如下

C++中被遺棄的多重繼承是什么

        由上面的關系圖我們可以看出它們指向的地址確實是不一樣的,一個指向的是子類對象的頭部,另一個指向的是腰部,此問題無解。

        多重繼承的問題之二是可能會產生冗余的成員,如下圖

C++中被遺棄的多重繼承是什么

        在上面的這幅圖中,Teacher 類和 Student 類繼承自 People 類,Doctor 類繼承自 Teacher 類 和 Student 類。就是一個在讀的博士原來是某學校的老師,但是他后來考上了在讀的博士,因此他也成了學生。所以他有多重身份,Teacher 會繼承 People 類的姓名和年齡,Student 也會繼承 People 類的姓名和年齡,這便造成了成員的冗余。下來我們以代碼為例來進行分析

#include <iostream>
#include <string>

using namespace std;

class People
{
    string m_name;
    int m_age;
public:
    People(string name, int age)
    {
        m_name = name;
        m_age = age;
    }
    
    void print()
    {
        cout << "name = " << m_name << ", "
             << "age = " << m_age << endl;
    }
};

class Teacher : public People
{
public:
    Teacher(string name, int age) : People(name, age)
    {
    }
};

class Student : public People
{
public:
    Student(string name, int age) : People(name, age)
    {
    }
};

class Doctor : public Teacher, public Student
{
public:
    Doctor(string name, int age) : Teacher(name, age), Student(name, age)
    {
    }
};

int main()
{
    Doctor d("zhang san", 22);
    
    d.print();
    
    return 0;
}

        我們來編譯下看看

C++中被遺棄的多重繼承是什么

        編譯的時候報錯了,它說不知道該調用哪個 print 函數。那么我們在 main 函數中指定,分別來調用Teacher 和 Student 的 print 函數來看看

C++中被遺棄的多重繼承是什么

        我們看到它打印了兩次,這邊造成了信息的冗余。當多重繼關系出現閉合時將產生數據冗余的問題!!!解決方案是采用虛繼承的方式。如下

C++中被遺棄的多重繼承是什么

        解決數據冗余問題的方案便是虛繼承。使得中間層不再關系頂層父類的初始化,最終子類必須直接調用頂層父類的構造函數。那么這時問題就來了,當在進行架構設計中需要繼承時,便無法確定是使用直接繼承還是虛繼承?如果我們采用直接繼承而且是多重繼承的話,便會產生數據的冗余;如果是虛繼承的話,是可以解決數據冗余的問題,但是在經過了好幾次的繼承之后,我們還會那么容易的找到頂層父類嗎?我們將上面的程序改為虛繼承,如下

#include <iostream>
#include <string>

using namespace std;

class People
{
    string m_name;
    int m_age;
public:
    People(string name, int age)
    {
        m_name = name;
        m_age = age;
    }
    
    void print()
    {
        cout << "name = " << m_name << ", "
             << "age = " << m_age << endl;
    }
};

class Teacher : virtual public People
{
public:
    Teacher(string name, int age) : People(name, age)
    {
    }
};

class Student : virtual public People
{
public:
    Student(string name, int age) : People(name, age)
    {
    }
};

class Doctor : public Teacher, public Student
{
public:
    Doctor(string name, int age) : People(name, age), Teacher(name, age), Student(name, age)
    {
    }
};

int main()
{
    Doctor d("zhang san", 22);
    
    d.print();
    
    return 0;
}

        編譯看看結果

C++中被遺棄的多重繼承是什么

        多重繼承的問題之三便是可能會產生多個虛函數表,如下

C++中被遺棄的多重繼承是什么

        下來我們還是以代碼為例來進行分析

#include <iostream>
#include <string>

using namespace std;

class BaseA
{
public:
    virtual void funcA()
    {
        cout << "BaseA::funcA()" << endl;
    }
};

class BaseB
{
public:
    virtual void funcB()
    {
        cout << "BaseB::funcB()" << endl;
    }
};

class Derived : public BaseA, public BaseB
{

};

int main()
{
    Derived d;
    BaseA* pa = &d;
    BaseB* pb = &d;
    BaseB* pbe = (BaseB*)pa;
    
    
    cout << "sizeof(d) = " << sizeof(d) << endl;
    
    cout << "Using pa to call funcA()..." << endl;
    
    pa->funcA();
    
    cout << "Using pb to call funcB()..." << endl;
    
    pb->funcB();
    
    cout << "Using pbe to call funcB()..." << endl;
    
    pbe->funcB();

    return 0;
}

        我們在程序的第 37 行打印對象 d 的內存大小,由于它虛繼承了兩個類,所以會產生兩個虛函數表指針,它的內存大小便會為 8。下來我們通過指針 pa 調用 funcA,很明顯它會打印出 BaseA::funcA(),而通過指針 pb 調用 funcB 便打印出 BaseB::funcB()。有意思的來了,我們之前在第 34 行用 BaseB 類型來強制轉換 BaseA 類型的指針 pa,我們通過它來打印下,看看會打印出什么。我們期望的是打印 BaseB::funcB(),看看結果呢

C++中被遺棄的多重繼承是什么

        我們看到前面打印的確實是如我們所分析的那樣,但是最后一個卻打印的是 funA 中的內容。我們很驚訝,我們在之前說過在 C++ 中要用新型的轉換關鍵字,繼承這便用的是 dynamic_cast,下來我們用它來進行轉換,再來打印這幾個指針的地址值。

C++中被遺棄的多重繼承是什么

        我們看到打印的是我們所期望的內容。而且用強制類型轉換的指針 pbe 和用 dynamic_cast 關鍵字轉換的指針 pbc 打印的地址值是不一樣的。所以在需要進行強制類型轉換時,我們要使用新式類型轉換關鍵字。解決方案便是使用 dynamic_cast,如下

C++中被遺棄的多重繼承是什么

        那么多重繼承這么多的問題,是不是就不用它了呢?不用的話,生活中的很多現象就用語言沒法描述了。因此,我們應該要正確的使用多重繼承,那么在工程開發者的“多重繼承”方式什么呢?單繼承某個類 + 實現(多個)接口。如下

C++中被遺棄的多重繼承是什么

        在經過這么多年的發展以后,前輩們便在實際工程中總結出了這些建議:a> 先繼承自一個類,然后實現多個接口;b> 父類提供 equal() 成員函數;c> equal() 成員函數用于判斷指針是否指向當前對象;d> 與多重繼承相關的強制類型轉換用 dynamic_cast 完成。

        下來我們還是以代碼為例進行分析

#include <iostream>
#include <string>

using namespace std;

class Base
{
protected:
    int mi;
public:
    Base(int i)
    {
        mi = i;
    }
    
    int getI()
    {
        return mi;
    }
    
    bool equal(Base* obj)
    {
        return (this == obj);
    }
};

class Interface1
{
public:
    virtual void add(int i) = 0;
    virtual void minus(int i) = 0;
};

class Interface2
{
public:
    virtual void multiply(int i) = 0;
    virtual void divide(int i) = 0;
};

class Derived : public Base, public Interface1, public Interface2
{
public:
    Derived(int i) : Base(i)
    {
    }
    
    void add(int i)
    {
        mi += i;
    }
    
    void minus(int i)
    {
        mi -= i;
    }
    
    void multiply(int i)
    {
        mi *= i;
    }
    
    void divide(int i)
    {
        if( i != 0 )
        {
            mi /= i;
        }
    }
};

int main()
{
    Derived d(100);
    Derived* p = &d;
    Interface1* pInt1 = &d;
    Interface2* pInt2 = &d;
    
    cout << "p->getI() = " << p->getI() << endl;    // 100
    
    pInt1->add(10);
    pInt2->divide(11);
    pInt1->minus(5);
    pInt2->multiply(8);
    
    cout << "p->getI() = " << p->getI() << endl;    // 40
    
    cout << endl;
    
    cout << "pInt1 == p : " << p->equal(dynamic_cast<Base*>(pInt1)) << endl;
    cout << "pInt2 == p : " << p->equal(dynamic_cast<Base*>(pInt2)) << endl;
    
    return 0;
}

        我們定義了一個父類,定義了兩個接口。類 Derived 為多重繼承,初始化為 100,在第 79 行便會打印出 100,經過下面四步的操作之后,得到的結果應該是 40。第 90 和 91 行打印的應該都為 1,我們看看編譯結果

C++中被遺棄的多重繼承是什么

“C++中被遺棄的多重繼承是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

c++
AI

龙泉市| 云霄县| 东宁县| 汉源县| 独山县| 北流市| 明光市| 离岛区| 华安县| 陕西省| 秦皇岛市| 蓬溪县| 响水县| 沙雅县| 乐陵市| 壶关县| 石城县| 利津县| 广河县| 彭阳县| 塘沽区| 岫岩| 东乡族自治县| 宜宾县| 新田县| 津市市| 荆州市| 定南县| 河东区| 巴中市| 浮梁县| 巴楚县| 平南县| 木兰县| 韩城市| 大田县| 黑龙江省| 鲁甸县| 渑池县| 黔西| 蚌埠市|