1. 程式人生 > 實用技巧 >【C++課程學習10】繼承

【C++課程學習10】繼承

目錄

參考

  • 範磊C++(第12課時)

筆記

繼承和派生的基本概念

  • 什麼是繼承和派生

  • 複雜的繼承和派生

  • 繼承和派生如何在C++中實現?

派生型別(派生許可權)的概念,以後會講到。

單一繼承

只有一個基類

#include <iostream>
using namespace std;
class Father
{
private:
    int fatherHight,fatherWeight;
public://建構函式只有一個引數,與下面的對應!
    void setFatherHight(int x){fatherHight=x;}
    void setFatherWeight(int x){fatherWeight=x;}
    void getFatherHightAndWeight(){cout<<"身高為"<<fatherHight<<endl;
        cout<<"體重為"<<fatherWeight<<endl;}

};

class Son :public Father
{
private:
    int sonWidth,sonLong;
public:
    void setSonHWidth(int x){sonWidth=x;}
    void setSonWLong(int x){sonLong=x;}
    void getsonHightAndWeight(){cout<<"肩寬為"<<sonWidth<<endl;
        cout<<"臂長為"<<sonLong<<endl;}


};

int main(int argc, const char * argv[]) {
    Son LiMing;
    LiMing.setFatherHight(180);
    LiMing.setFatherWeight(80);
    LiMing.setSonWLong(134);
    LiMing.setSonHWidth(65);
    LiMing.getsonHightAndWeight();
    LiMing.getFatherHightAndWeight();
    return 0;
}

輸出結果:

保護成員

#include <iostream>
using namespace std;
class Father
{
//private://子類不能訪問
protected://只能子類來訪問
    int fatherHight,fatherWeight;
public://建構函式只有一個引數,與下面的對應!
    void setFatherHight(int x){fatherHight=x;}
    void setFatherWeight(int x){fatherWeight=x;}
    //void getFatherHightAndWeight(){cout<<"身高為"<<fatherHight<<endl;
      //  cout<<"體重為"<<fatherWeight<<endl;}

};

class Son :public Father
{
private:
    int sonWidth,sonLong;
public:
    void setSonHWidth(int x){sonWidth=x;}
    void setSonWLong(int x){sonLong=x;}
    //void getsonHightAndWeight(){cout<<"肩寬為"<<sonWidth<<endl;
      //  cout<<"臂長為"<<sonLong<<endl;}
    void PrintAll(){
        cout<<"肩寬為"<<sonWidth<<endl;
        cout<<"臂長為"<<sonLong<<endl;
        cout<<"身高為"<<fatherHight<<endl;
        cout<<"體重為"<<fatherWeight<<endl;
    }


};

int main(int argc, const char * argv[]) {
    Son LiMing;
    LiMing.setFatherHight(180);
    LiMing.setFatherWeight(80);
    LiMing.setSonWLong(134);
    LiMing.setSonHWidth(65);
    //LiMing.getsonHightAndWeight();
    //LiMing.getFatherHightAndWeight();
    LiMing.PrintAll();
    return 0;
}

輸出結果:

共有派生

  • 共有

  • 保護

  • 私有

繼承的賦值

子類可以賦值給父類,但父類不能給子類。
因為父類的成員數少。
同樣,基類的指標可以指向派生類物件,但是派生類指標不能指向基類物件。


私有派生(繼承)

#include <iostream>
using namespace std;
class Father
{
public:
    void room(){cout<<"父親的大房子我可以享受"<<endl;}
};//注意分號

class Son: private Father
{
public:
    void enjoy(){room();}
};

int main(int argc, const char * argv[]) {
    Son a;
    a.enjoy();
    return 0;
}

輸出結果:

多重繼承

#include <iostream>
using namespace std;
class Father
{
public:
    void setA(int a ){tall=a;}
    void print1(){cout<<"身高的值:"<<tall<<endl;}
private:
    int tall;
};

class Mother
{
public:
    void setB(int a ){weight=a;}
    void print2(){cout<<"體重的值:"<<weight<<endl;}//成員函式名字最好不要相同,否則會報錯!
private:
    int weight;
};

class Son: public Father,public Mother
{
public:
    void setC(int a ){age=a;}
    void print3(){print1();print2();cout<<"年齡的值:"<<age<<endl;}
private:
    int age;
};

int main(int argc, const char * argv[]) {
    Son Mike;
    Mike.setA(175);
    Mike.setB(80);
    Mike.setC(25);
    Mike.print3();
    return 0;
}

輸出:

當然同樣的也可以設定派生許可權。

繼承的構造與構析

建構函式和解構函式的執行順序。

基類的構造順序是按繼承時的給定順序執行。
析構時則正好相反。

向基類建構函式傳遞引數

  • 方法1
    方法正確,但是呼叫父類的建構函式對建立子類物件沒有幫助,( 無用的建構函式)這相當於浪費了系統的開銷。
#include <iostream>
#include<string>
using namespace std;
class Father
{
public:
    Father(){cout<<"構造基類物件"<<endl;}
    ~Father(){cout<<"析構基類物件"<<endl;}
    void setA(int a ){tall=a;}
    void print(){cout<<name<<"身高的值:"<<tall<<"cm"<<endl;}
protected:
    string name;
    int tall;
private:

};

class Son :public Father
{
public:
    Son(string a, int i, int j){
        name=a;
        tall=i;
        weight=j;
        cout<<"構造子類物件"<<endl;}
    ~Son(){cout<<"析構子類物件"<<endl;}
    void setA(int a ){tall=a;}
    void print1(){print();cout<<"體重的值:"<<weight<<"kg"<<endl;}//不能覆蓋掉父類的,因此要改名。
protected:
    int weight;
private:
};

int main(int argc, const char * argv[]) {
    Son Mike("Mike",180,80);
    Mike.print1();
    cout<<"程式結束"<<endl;
    return 0;
}

輸出:

  • 方法2
    充分利用基類的建構函式。
#include <iostream>
#include<string>
using namespace std;
class Father
{
public:
    //Father(){cout<<"構造基類物件"<<endl;}
    Father(string a, int i){
        name=a;
        tall=i;
        cout<<"構造帶兩個引數的基類物件"<<endl;}
    ~Father(){cout<<"析構基類物件"<<endl;}
    void setA(int a ){tall=a;}
    void print(){cout<<name<<"身高的值:"<<tall<<"cm"<<endl;}
protected:
    string name;
    int tall;
private:

};

class Son :public Father
{
public:
    Son(string a, int i, int j):Father(a,i){
        weight=j;
        cout<<"構造子類物件"<<endl;}
    ~Son(){cout<<"析構子類物件"<<endl;}
    void setA(int a ){tall=a;}
    void print1(){print();cout<<"體重的值:"<<weight<<"kg"<<endl;}//不能覆蓋掉父類的,因此要改名。
protected:
    int weight;
private:
};

int main(int argc, const char * argv[]) {
    Son Mike("Mike",180,80);//
    Mike.print1();
    cout<<"程式結束"<<endl;
    return 0;
}

輸出:

多重繼承容易產生兩義性

成員重名導致的問題。
會產生警告⚠️
強行執行的話,就會產生覆蓋問題。
可以使用作用域操作符來避免這個問題。

兩義性的歸屬問題

繼承中的過載

一旦子類定義了建構函式,基類中的建構函式就會被覆蓋。
【問題】const函式,只能由const物件呼叫嗎???