欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++詳細(xì)講解繼承與虛繼承實(shí)現(xiàn)

 更新時(shí)間:2022年04月15日 11:24:45   作者:m0_52012656  
這篇文章主要介紹了Java中的繼承詳情,繼承是面向?qū)ο笕筇卣髦?,可以使得子類具有父類的屬性和方法,還可以在子類中重新定義,以及追加屬性和方法,下文介紹需要的朋友可以參考下

繼承的概念及定義

概念:

繼承機(jī)制是面向?qū)ο蟪绦蛟O(shè)計(jì)為了提高代碼復(fù)用率的一種手段,它可以保持原類特性的基礎(chǔ)上進(jìn)行拓展,簡(jiǎn)單來說繼承是類層次的復(fù)用。

接下來我們來看一個(gè)簡(jiǎn)單的繼承

class Person
{
public:
    void Print()
    {
        cout<<"name:"<<_name<<endl;
        cout<<"age:"<<_age<<endl;
    }
protected:
    string _name="zhao";
    int _age=18;
};
class Student : public Person
{
protected:
    int _stuid;
};
class Teacher :public Person
{
protected:
    int _jobid;
};

在上面這個(gè)類中繼承后父類(Person)的成員都會(huì)變成子類的一部分。

定義:

格式:

class 子類:

public 父類{ };

繼承關(guān)系和訪問限定符

繼承基類成員訪問方式的變化

類成員/繼承方式public繼承protected繼承private繼承
基類的public成員派生類的public成員派生類的protected成員派生類的private成員
基類的protected成員派生類的protected成員派生類的protected成員派生類的private成員
基類的private成員在派生類中不可見在派生類中不可見在派生類中不可見

總結(jié)

  • 基類private成員在派生類中無論以什么方式繼承都是不可見的。這里的不可見是指基類的私有成員還是被繼承到了派生類對(duì)象中,但是語法上限制派生類對(duì)象不管在類里面還是類外面都不能去訪問它。
  • 基類private成員在派生類中是不能被訪問,如果基類成員不想在類外直接被訪問,但需要在派生類中能訪問,就定義為protected。可以看出保護(hù)成員限定符是因繼承才出現(xiàn)的。
  • 實(shí)際上面的表格我們進(jìn)行一下總結(jié)會(huì)發(fā)現(xiàn),基類的私有成員在子類都是不可見?;惖钠渌蓡T在子類的訪問方式 == Min(成員在基類的訪問限定符,繼承方式),public > protected > private。
  • 使用關(guān)鍵字class時(shí)默認(rèn)的繼承方式是private,使用struct時(shí)默認(rèn)的繼承方式是public,不過最好顯示的寫出繼承方式。
  • 在實(shí)際運(yùn)用中一般使用都是public繼承,幾乎很少使用protetced/private繼承,也不提倡使用protetced/private繼承,因?yàn)閜rotetced/private繼承下來的成員都只能在派生類的類里面使用,實(shí)際中擴(kuò)展維護(hù)性不強(qiáng)。

基類和派生類對(duì)象賦值轉(zhuǎn)換

派生類對(duì)象可以賦值給基類的對(duì)象/指針/引用。這里有一個(gè)形象的書法叫做切片或切割

基類對(duì)象不能賦值給派生類對(duì)象

基類的指針可以通過強(qiáng)制類型轉(zhuǎn)換賦值給派生類的指針。但是必須是基類的指針是指向派生類對(duì)象時(shí)才是安全地。

繼承中的作用域

在繼承體系中基類和派生類都有獨(dú)立的作用域。

子類和父類中有同名成員;子類成員將屏蔽父類對(duì)同名成員的直接訪問,這種情況叫做隱藏,也叫作重定義。如果要訪問父類的成員可以使用域作用限定符進(jìn)行訪問。

注意函數(shù)構(gòu)成隱藏的話只需要函數(shù)名相同。

實(shí)際在繼承體系里面最好不要定義同名的成員。

派生類的默認(rèn)成員函數(shù)

在這里又把類與對(duì)象中學(xué)的六個(gè)默認(rèn)成員函數(shù)拉出來了,那么在繼承體系中這幾個(gè)成員函數(shù)是如何生成的呢?

  • 構(gòu)造函數(shù):派生類的構(gòu)造函數(shù)必須基類的構(gòu)造函數(shù)初始化基類的那部分成員。如果基類沒有默認(rèn)的構(gòu)造函數(shù),則必須在派生類構(gòu)造函數(shù)的初始化列表階段顯示調(diào)用。
  • 拷貝構(gòu)造函數(shù):派生類的拷貝構(gòu)造函數(shù)必須調(diào)用基類的拷貝構(gòu)造完成基類的拷貝初始化。
  • 賦值重載:派生類operator=必須要調(diào)用基類的operator=完成基類的賦值。
  • 析構(gòu)函數(shù):派生類的析構(gòu)函數(shù)會(huì)在被調(diào)用完成后自動(dòng)調(diào)用基類的析構(gòu)函數(shù)清理基類成員。因?yàn)檫@樣才能保證派生類對(duì)象先清理派生類成員再清理基類成員的順序。

派生類對(duì)象初始化先調(diào)用基類構(gòu)造再調(diào)派生類構(gòu)造

派生類對(duì)象析構(gòu)清理先調(diào)用派生類析構(gòu)再調(diào)基類的析構(gòu)。

簡(jiǎn)單的運(yùn)用:

class Person
{
public:
    Person(const  char* name="zhao")
        :_name(name)
        {
            cout<<"父構(gòu)造"<<endl;
        }
    Person(const Person& p)
        :_name(p.name)
        {
            cout<<"父拷貝構(gòu)造"<<endl;
        }
    Person& operator=(const Person& p)
    {
        cout<<"父賦值重載"<<endl;
        if(this!=&p)
            _name=p.name;
        return *this;
            
    }
    ~Person()
    {
        cout<<"父析構(gòu)"<<endl;
    }
protected:
    string _name;
};
class Student:public Person
{
public:
    Student(const char* name,int num)
        :Person(name)
        ,_num(num)
    {
        cout<<"子構(gòu)造"<<endl;
    }
    Student(const Student& s)
        :Person(s)
        ,_num(num)
    {
        cout<<"子拷貝構(gòu)造"<<endl;
    }
    Student& operator=(const Student& s)
    {
        cout<<"子賦值重載"<<endl;
        if(this!=&s)
        {
        //小心這里是隱藏
            Person::operator=(s);
            _num=s._num;
        }
        return *this;
    }
    //需要注意在這塊~Student()和~Person()構(gòu)成隱藏,這是由于多態(tài)的一些原因,任何類析構(gòu)函數(shù)名都會(huì)被統(tǒng)一處理為destructor()
    ~Student()
    {
        cout<<"子析構(gòu)"<<endl;
        //為了保證析構(gòu)時(shí),保持先子再父的后進(jìn)先出的析構(gòu)順序,子類析構(gòu)函數(shù)完成后,會(huì)自動(dòng)去調(diào)用父類的析構(gòu)函數(shù)。
    }
protected:
    int _num;
    
};

繼承與友元

友元關(guān)系不能繼承,也就是說基類友元不是子類的友元。

繼承與靜態(tài)成員

基類定義了static靜態(tài)成員,則整個(gè)繼承體系里面只有一個(gè)這樣的成員,無論派生出多少個(gè)子類,都只有一個(gè)static成員實(shí)例。

class Person
{
public :
    Person () {++ _count ;}
protected :
    string _name ; // 姓名
public :
    static int _count; // 統(tǒng)計(jì)人的個(gè)數(shù)。
};
int Person :: _count = 0;
class Student : public Person
{
protected :
    int _stuNum ; // 學(xué)號(hào)
};
class Graduate : public Student
{
protected :
    string _seminarCourse ; // 研究科目
};
void TestPerson()
{
    Student s1 ;
    Student s2 ;
    Student s3 ;
    Graduate s4 ;
    cout <<" 人數(shù) :"<< Person ::_count << endl;
    Student ::_count = 0;
    cout <<" 人數(shù) :"<< Person ::_count << endl;
}

復(fù)雜的菱形繼承及菱形虛擬繼承

單繼承:一個(gè)子類只有一個(gè)直接父類時(shí)稱這個(gè)繼承關(guān)系為單繼承

多繼承:一個(gè)子類有兩個(gè)或以上直接父類時(shí)稱這個(gè)繼承關(guān)系為多繼承

菱形繼承:菱形繼承是多繼承的一種特殊情況。

菱形繼承的問題:從下面的對(duì)象成員模型構(gòu)造,可以看出菱形繼承有數(shù)據(jù)冗余和二義性的問題。在Assistant的對(duì)象中Person成員會(huì)有兩份。

虛擬繼承可以解決菱形繼承的二義性和數(shù)據(jù)冗余的問題。如上面的繼承關(guān)系,在Student和Teacher的繼承Person時(shí)使用虛擬繼承,即可解決問題。需要注意的是,虛擬繼承不要在其他地方去使用

虛擬繼承解決數(shù)據(jù)冗余和二義性的原理為了研究虛擬繼承原理,我們給出了一個(gè)簡(jiǎn)化的菱形繼承繼承體系,再借助內(nèi)存窗口觀察對(duì)象成員的模型。

虛繼承原理

虛繼承實(shí)現(xiàn):

在腰部?jī)蓚€(gè)繼承之前加上關(guān)鍵字vittul,實(shí)現(xiàn)虛繼承。

class Animal{
    public:
    int _a;
}
class Tuo:virtual public Animal
{
    public:
    int _b;
}
class Sheep:virtual public Animal
{
    public:
    int _c;
}
class SheepTuo:public B ,public C
{
    public:
    int _b;
}

要探究虛繼承如何實(shí)現(xiàn),需要借用VS的開發(fā)人員命令提示工具,在VS2019的工具->命令行->開發(fā)者命令提示中。cd到當(dāng)前項(xiàng)目的目錄,輸入cl /d1reportSingleClassLayout"要查看的類名" “文件名”,在這里就是cl/d1reportSingleClassLayoutSheepTuo diamond_Inherit.cpp??梢钥吹疆?dāng)前類內(nèi)存的結(jié)構(gòu)。(編譯后才能查看到內(nèi)存分布)

這個(gè)圖就是內(nèi)存結(jié)構(gòu),可以看到,SheepTuo類中分別繼承了來自Sheep類的vbptr(虛基類指針)和Tuo類的vbptr(虛基類指針)。這個(gè)虛基類指針指向的是一個(gè)虛基類表,可以在圖中看到虛基類表中第一項(xiàng)存儲(chǔ)的是vbptr與本類的偏移地址,也就是繼承過來的Sheep類中初始位置就是存放Sheep類的的vbptr,在這里為0;第二項(xiàng)是本類的vbptr與虛基類的公有成員之間的偏移量,也就是Sheep的vbptr和Animal類的age之間偏移為8,Tuo的vbptr和age之間偏移量為4。對(duì)于虛基類的派生類,虛基類的偏移量由實(shí)際類型決定,因此在運(yùn)行時(shí)才可以確定虛基類的地址。

指的注意的是,Sheep類中也是存放了一份age,在這里還可以看到,Sheep和Tuo的Size都是8,因?yàn)槌死^承的age以外,還有Size為4的虛函數(shù)指針

因?yàn)閏lass SheepTuo :public Sheep, public Tuo繼承的時(shí)候,把Sheep和Tuo的vbptr都繼承了,然后通過他們類距離虛基類中的公共成員age的偏移量發(fā)現(xiàn)他們指向的是同一個(gè)age,所以就不會(huì)拷貝兩份,SheepTuo只保留一份age。至于虛繼承底層實(shí)現(xiàn)原理則與編譯器相關(guān)

繼承的總結(jié)

很多人說C++語法復(fù)雜,其實(shí)多繼承就是一個(gè)體現(xiàn)。有了多繼承,就存在菱形繼承,有了菱形繼承就有菱形虛擬繼承,底層實(shí)現(xiàn)就很復(fù)雜。所以一般不建議設(shè)計(jì)出多繼承,一定不要設(shè)計(jì)出菱形繼承。否則在復(fù)雜度及性能上都有問題。

多繼承可以認(rèn)為是C++的缺陷之一,很多后來的OO語言都沒有多繼承,如Java

繼承和組合

public繼承是一種is-a的關(guān)系。也就是說每個(gè)派生類對(duì)象都是一個(gè)基類對(duì)象。

組合是一種has-a的關(guān)系。假設(shè)B組合了A,每個(gè)B對(duì)象中都有一個(gè)A對(duì)象。

優(yōu)先使用對(duì)象組合,而不是類繼承 。

繼承允許你根據(jù)基類的實(shí)現(xiàn)來定義派生類的實(shí)現(xiàn)。這種通過生成派生類的復(fù)用通常被稱為白箱復(fù)用(white-box reuse)。術(shù)語“白箱”是相對(duì)可視性而言:在繼承方式中,基類的內(nèi)部細(xì)節(jié)對(duì)子類可見 。繼承一定程度破壞了基類的封裝,基類的改變,對(duì)派生類有很大的影響。派生類和基類間的依賴關(guān)系很強(qiáng),耦合度高。

對(duì)象組合是類繼承之外的另一種復(fù)用選擇。新的更復(fù)雜的功能可以通過組裝或組合對(duì)象來獲得。對(duì)象組合要求被組合的對(duì)象具有良好定義的接口。這種復(fù)用風(fēng)格被稱為黑箱復(fù)用(black-box reuse),因?yàn)閷?duì)象的內(nèi)部細(xì)節(jié)是不可見的。對(duì)象只以“黑箱”的形式出現(xiàn)。 組合類之間沒有很強(qiáng)的依賴關(guān)系,耦合度低。優(yōu)先使用對(duì)象組合有助于你保持每個(gè)類被封裝。

實(shí)際盡量多去用組合。組合的耦合度低,代碼維護(hù)性好。不過繼承也有用武之地的,有些關(guān)系就適合繼承那就用繼承,另外要實(shí)現(xiàn)多態(tài),也必須要繼承。類之間的關(guān)系可以用繼承,可以用組合,就用組合

到此這篇關(guān)于C++詳細(xì)講解繼承與虛繼承實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)C++ 繼承內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語言實(shí)現(xiàn)簡(jiǎn)易版掃雷游戲

    C語言實(shí)現(xiàn)簡(jiǎn)易版掃雷游戲

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)簡(jiǎn)易版掃雷游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-05-05
  • STL常用容器詳細(xì)解析

    STL常用容器詳細(xì)解析

    這里我們不涉及容器的基本操作之類,只是要討論一下各個(gè)容器其各自的特點(diǎn)STL中的常用容器包括:順序性容器(vector、deque、list)、關(guān)聯(lián)容器(map、set)、容器適配器(queue、stac)
    2013-09-09
  • C++11計(jì)時(shí)器之chrono庫簡(jiǎn)介

    C++11計(jì)時(shí)器之chrono庫簡(jiǎn)介

    C++11有了chrono庫,可以在不同系統(tǒng)中很容易的實(shí)現(xiàn)定時(shí)功能,要使用chrono庫,需要#include,其所有實(shí)現(xiàn)均在std::chrono namespace下,本文給大家介紹C++11計(jì)時(shí)器:chrono庫介紹,感興趣的朋友一起看看吧
    2023-12-12
  • Qt編寫地圖之實(shí)現(xiàn)跨平臺(tái)功能

    Qt編寫地圖之實(shí)現(xiàn)跨平臺(tái)功能

    這篇文章主要介紹了如何利用Qt編寫地圖應(yīng)用時(shí)實(shí)現(xiàn)跨平臺(tái)功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-02-02
  • C語言實(shí)現(xiàn)數(shù)據(jù)的壓縮與解壓

    C語言實(shí)現(xiàn)數(shù)據(jù)的壓縮與解壓

    數(shù)據(jù)壓縮是通過一系列的算法和技術(shù)將原始數(shù)據(jù)轉(zhuǎn)換為更緊湊的表示形式,以減少數(shù)據(jù)占用的存儲(chǔ)空間,數(shù)據(jù)解壓縮則是將壓縮后的數(shù)據(jù)恢復(fù)到原始的表示形式,本文給大家詳細(xì)介紹了C語言實(shí)現(xiàn)數(shù)據(jù)壓縮與解壓,需要的朋友可以參考下
    2023-08-08
  • C++使用遞歸函數(shù)和棧操作逆序一個(gè)棧的算法示例

    C++使用遞歸函數(shù)和棧操作逆序一個(gè)棧的算法示例

    這篇文章主要介紹了C++使用遞歸函數(shù)和棧操作逆序一個(gè)棧的算法,結(jié)合實(shí)例形式分析了C++遞歸函數(shù)與逆序棧的相關(guān)操作技巧,需要的朋友可以參考下
    2017-05-05
  • 純C語言實(shí)現(xiàn)火車售票系統(tǒng)

    純C語言實(shí)現(xiàn)火車售票系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了純C語言實(shí)現(xiàn)火車售票系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • C++ const引用、臨時(shí)變量 引用參數(shù)詳解

    C++ const引用、臨時(shí)變量 引用參數(shù)詳解

    下面小編就為大家?guī)硪黄狢++ const引用、臨時(shí)變量 引用參數(shù)詳解。小編覺得挺不錯(cuò)的現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-01-01
  • 利用C++求解八數(shù)碼問題實(shí)例代碼

    利用C++求解八數(shù)碼問題實(shí)例代碼

    所謂八數(shù)碼問題是指這樣一種游戲,將分別標(biāo)有數(shù)字1,2,3,…,8的八塊正方形數(shù)碼牌任意地放在一塊3×3的數(shù)碼盤上,放牌時(shí)要求不能重疊,下面這篇文章主要給大家介紹了關(guān)于利用C++求解八數(shù)碼問題的相關(guān)資料,需要的朋友可以參考下
    2022-11-11
  • 華為機(jī)試題之統(tǒng)計(jì)單詞個(gè)數(shù)實(shí)例代碼

    華為機(jī)試題之統(tǒng)計(jì)單詞個(gè)數(shù)實(shí)例代碼

    這篇文章主要介紹了華為機(jī)試題之統(tǒng)計(jì)單詞個(gè)數(shù)實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-05-05

最新評(píng)論