C++:繼承


一、繼承:ide

經過繼承定義一個類,它們的類型之間的關係建模,共享共有的東西,實現各自本質不一樣的東西。函數

C++的「繼承」特性能夠提升程序的可複用性。ui

繼承定義格式:this


wKiom1cIoCPD6ffCAAAkHgWtV5E225.png


二、類的大小:spa

class Base3d

{指針

public:orm

    Base(int data)對象

    {blog

        cout << data << endl;

        cout << "Base()" << this << endl;

    }

    ~Base()

    {

        cout << "~Base()" << endl;

    }

private:

    int _pri;

protected:

    int _pro;

public:

    int _pub;

};   

//求類大小時,只求數據成員的大小三個int類型的數據成員,因此大小爲12

class Base1

{

public:

    Base1(int data)

    {

        cout << "Base1()" << endl;

    }

    ~Base1()

    {

        cout << "~Base1()" << endl;

    }

};

//當類沒有數據成員時,一般系統都會給一個值爲1的空間,由於類的大小不可能爲0,可是系統又要給類分配空間,爲了節省空間,會分配最小空間

class Test

{

public:

    Test(int data)

    {

        cout << "Test()" << endl;

    }

    ~Test()

    {

        cout << "~Test()" << endl;

    }

};

class Derive :public Base, public Base1

{

public:

    Derive()

        :d(10)

        , Base1(10)

        , Base(20)

    {

        cout << "Derive()" << this << endl;

    }

    ~Derive()

    {

        cout << "~Derive()" << endl;

    }

private:

    int _dPri;

protected:

    int _dPro;

public:

    int _dPub;

    int _pri;

    Test d;

};

int main()

{

    cout << sizeof(Base) << endl;  //12

    cout << sizeof(Base1) << endl;  //1

    cout << sizeof(Derive) << endl;  //32

    system("pause");

    return 0;

}

wKioL1cLTLOhj8FFAABMhx2umdo195.png

三、類的訪問:

class Base

{

public:

    Base(int data)

    {

        cout << data << endl;

        cout << "Base()" << this << endl;

    }

    void Show()

    {

        cout << "Base::Show()" << endl;

        cout << "_pri=" << _pri << endl;

        cout << "_pro=" << _pro << endl;

        cout << "_pub=" << _pub << endl;

    }

    ~Base()

    {

        cout << "~Base()" << endl;

    }

private:

    int _pri;

protected:

    int _pro;

public:

    int _pub;

};

class Base1

{

public:

    Base1(int data)

    {

        cout << "Base1()" << endl;

    }

    ~Base1()

    {

        cout << "~Base1()" << endl;

    }

};

class Test

{

public:

    Test(int data)

    {

        cout << "Test()" << endl;

    }

    ~Test()

    {

        cout << "~Test()" << endl;

    }

};

class Derive :public Base, public Base1

{

public:

    Derive()

        :d(10)

        , Base1(10)

        , Base(20)

    {

        cout << "Derive()" << this << endl;

    }

    ~Derive()

    {

        cout << "~Derive()" << endl;

    }

    void Display()

    { 

        cout << "_pri=" << _pri << endl;

        cout << "_pro=" <<& _pro << endl;

        cout << "-pub=" << &_pub << endl;

        cout << "_dPri=" << &_dPri << endl;

        cout << "_dPro=" << &_dPro << endl;

        cout << "_dPub=" << &_dPub << endl;

    }

    void Show()

    {

        _pri = 10;

        //Base::_pri = 10;  

        //私有成員只能在基類訪問,在派生類和其餘地方都不能訪問 

        cout << "Derive::Show()" << endl;

    }

private:

    int _dPri;

protected:

    int _dPro;

public:

    int _dPub;

    int _pri;

    Test d;

};

int main()

{

    cout << sizeof(Base) << endl;  //12

    cout << sizeof(Base1) << endl;  //1

    cout << sizeof(Derive) << endl;  //32

    Derive d; 

    //調用構造函數時,先進Base類調用構造函數初始化Base,再進Base1初始化Base1

    //最後再進Test類初始化對象d,由於d是在派生類中建立的,因此要最後初始化,

    //Base和Base1初始化順序按照繼承順序執行,並不按照派生類中初始化列表中的順序進行

    d.Show();  

    //調用派生類中的函數Show(),在函數中_pri(派生類中的公有成員_pri)被賦值爲10,

    //子類和父類中有同名成員,子類成員將屏蔽父類對成員的直接訪問

   d.Base::Show();  

    //調用基類Base中的Show(),由於都未賦值,因此顯示的都爲隨機值

    d.Display();

    //_pri(派生類中的)顯示爲10,其餘顯示的地址,都相差4字節,說明在類中,開闢的地址是連續的

    d._dPub = 10;

    d.Show();

    //d._dPro = 20;    //保護成員在類外不能夠訪問

    system("pause");

    return 0;

}

運行結果:(運行環境是VS2013)

wKioL1cLTZyw5LZ2AAAybp3NeDg446.png



wKiom1cIoACDo1XoAAB81ZKuMk8489.png

總結:

一、基類的private成員在派生類中是不能被訪問的。

二、若是基類成員不想在類外直接被訪問,但須要在派生類中能訪問,就定義爲protected。保護成員限定符是因繼承纔出現的。

三、public繼承是一個接口繼承,保持is-a原則,每一個父類可用的成員對子類也可用,由於每一個子類對象也都是一個父類對象。

四、protetced/private繼承是一個實現繼承,基類的部分紅員並不是徹底成爲子類接口的一部分,是 has-a 的關係原則,因此非特殊狀況下不會使用這兩種繼承關係,在絕大多數的場景下使用的都是公有繼承。

五、不論是哪一種繼承方式,在派生類內部均可以訪問基類的公有成員和保護成員,基類的私有成員存在可是在子類中不可見(不能訪問)。

六、使用關鍵字class時默認的繼承方式是private,使用struct時默認的繼承方式是public,不過最好顯示的寫出繼承方式。

七、在實際運用中通常使用都是public繼承,極少場景下才會使用protetced/private繼承.

一、私有成員只能在基類訪問,在派生類和其餘地方都不能訪問 

二、保護成員在類外不能夠訪問

三、在派生類中初始化基類時,系統會按照繼承的前後順序依次調用相應的構造函數來初始化,而不是根據初始化列表中的順序

一、在繼承體系中基類和派生類是兩個不一樣做用域。

二、子類和父類中有同名成員,子類成員將屏蔽父類對成員的直接訪問。(在子類成員函數中,可使用 基類::基類成員 訪問)--隱藏 --重定義

三、注意在實際中在繼承體系裏面最好不要定義同名的成員。


【繼承關係中構造函數調用順序】

wKioL1cIk5jwN5NOAAAscY_8knc587.png

【說明】

  一、基類沒有缺省構造函數,派生類必需要在初始化列表中顯式給出基類名和參數列表。

class Base

{

public:

   Base(int data)

  {  }

};

class Base1

{

public:

   Base1(int data)

   {  }

};

class Derive: public Base, public Base1

{

public:

    Derive()

      : Base1(10)

      , Base(20)


     {  }

};

     

  二、基類沒有定義構造函數,則派生類也能夠不用定義,所有使用缺省構造函數。

  三、基類定義了帶有形參表構造函數,派生類就必定定義構造函數。


【繼承關係中析構函數調用順序】

wKiom1cIkuijKCwFAAAooEarDD4689.png

四、友元與繼承及其賦值兼容:

class Base

{

public:

    friend void Display(Base b);

    Base(int data)

    {

        cout << data << endl;

        cout << "Base()" << this << endl;

       }

    ~Base()

    {

        cout << "~Base()" << endl;

    }

private:

    int _pri;

protected:

    int _pro;

public:

    int _pub;

};

class Derive :public Base

{

public:

    friend void Display(Base b);

    Derive()

        :Base(20)

    {

             cout << "Derive()" << this << endl;

    }

    ~Derive()

    {

        cout << "~Derive()" << endl;

    }

private:

    int _dPri;

protected:

    int _dPro;

public:

    int _dPub;

    int _pri;  

 //子類和父類中有同名成員,子類成員將屏蔽父類對成員的直接訪問

};

void Display(Base b)

{

    cout << b._pri << endl; 

    cout << b._pro << endl; 

    cout << b._pub << endl;

    Derive d;

    //cout << d._dPri << endl; 

    //友元關係不能繼承,基類友元不能訪問子類私有和保護成員

系統給出的錯誤提示: wKioL1cLTuvgyNkZAAAEfa8RUQc105.png

  //若是Display是基類Base的友元函數,則不能訪問派生類的私有和保護成員

    //若是Display是派生類的友元函數,則能夠訪問

}

int main()

{

    Derive d;   //子類對象

    Base b(0);   //父類對象

    b = d;  //子類對象能夠賦值給父類對象

    //d = b;   //父類對象不能夠賦值給子類對象

    Base*pBase = &d;  //父類指針

    Derive *pd = (Derive*)&b;  //子類指針

    pBase = pd;  //父類的指針/引用能夠指向子類對象

    //pd = pBase;    //子類的指針/引用不能指向父類對象 (能夠經過強制類型轉換實現)

    return 0;

}

系統給出的錯誤提示:

wKiom1cLTpjSpPFQAAAddUuz31g639.png

wKiom1cLTsHxDSV0AAAKF4IxS6w832.png

總結:

一、友元關係不能繼承,基類友元不能訪問子類私有和保護成員

二、子類對象能夠賦值給父類對象

三、父類對象不能夠賦值給子類對象

四、父類的指針/引用能夠指向子類對象

五、子類的指針/引用不能指向父類對象 (能夠經過強制類型轉換實現)

六、基類定義了static成員,則整個繼承體系裏面只有一個這樣的成員。


除了單繼承,還有多繼承和菱形繼承,如下可區別它們之間的區別:

                              wKiom1cImtTjhiZkAAAWqsxA9Mg290.png    

                        wKiom1cImtWAhDZ9AAAU-kwWhf0253.png

               wKiom1cInM_CdaCOAAAeRTrpFZU333.png

相關文章
相關標籤/搜索