C++:繼承


1、繼承:

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

C++的“繼承”特性可以提高程序的可複用性。

繼承定義格式:


wKiom1cIoCPD6ffCAAAkHgWtV5E225.png


2、類的大小:

class Base

{

public:

    Base(int data)

    {

        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

3、類的訪問:

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

總結:

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

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

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

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

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

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

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

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

2、保護成員在類外不可以訪問

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

1、在繼承體系中基類和派生類是兩個不同作用域。

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

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


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

wKioL1cIk5jwN5NOAAAscY_8knc587.png

【說明】

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

class Base

{

public:

   Base(int data)

  {  }

};

class Base1

{

public:

   Base1(int data)

   {  }

};

class Derive: public Base, public Base1

{

public:

    Derive()

      : Base1(10)

      , Base(20)


     {  }

};

     

  2、基類沒有定義構造函數,則派生類也可以不用定義,全部使用缺省構造函數。

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


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

wKiom1cIkuijKCwFAAAooEarDD4689.png

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

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

總結:

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

2、子類對象可以賦值給父類對象

3、父類對象不可以賦值給子類對象

4、父類的指針/引用可以指向子類對象

5、子類的指針/引用不能指向父類對象 (可以通過強制類型轉換實現)

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


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

                              wKiom1cImtTjhiZkAAAWqsxA9Mg290.png    

                        wKiom1cImtWAhDZ9AAAU-kwWhf0253.png

               wKiom1cInM_CdaCOAAAeRTrpFZU333.png





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章