1. 程式人生 > >C++奇淫技巧,程序員為啥天天學繼承與派生,真的有這麽難嗎

C++奇淫技巧,程序員為啥天天學繼承與派生,真的有這麽難嗎

輸出 構造 程序 繼承與派生 isp 一個 sha void 愛好

  • 繼承與派生
  • 1.1繼承與派生的概念

    在C++中,可重用性是通過繼承這一機制來實現的。所謂繼承,就是在一個已存在的類的基礎上建立一個新的類。已存在的類稱為基類,新建立的類成為派生類。(與對象的復制做區別)一個新類從已有的類那裏獲得其已有特性,這種現象稱為類的繼承。

    C++奇淫技巧,程序員為啥天天學繼承與派生,真的有這麽難嗎
    派生類繼承了基類的所有數據成員和成員函數,並可以對成員作必要的增加或調整。
    創一個小群,供大家學習交流聊天
    如果有對學C++方面有什麽疑惑問題的,或者有什麽想說的想聊的大家可以一起交流學習一起進步呀。
    也希望大家對學C++能夠持之以恒
    C++愛好群,
    如果你想要學好C++最好加入一個組織,這樣大家學習的話就比較方便,還能夠共同交流和分享資料,給你推薦一個學習的組織:快樂學習C++組織 可以點擊組織二字,可以直達


    技術分享圖片
    單繼承:一個派生類只從一個基類派生。

    多重繼承:一個派生類可以從多個基類派生。

    基類和派生類的關系:派生類是基類的具體化,而基類則是派生類的抽象。

    1.2 派生類的聲明方式

    聲明派生類的一般形式:

    class 派生類名: 集成方式 積累名

    {

    派生類新增加的成員;

    }

    Eg:假設已經聲明了一個基類Student

    class Student1: public Student //聲明基類是Student,集成方式是public

    {

    public:

    void display_1() //新增加的成員函數

    {

    cout<<”age:”<<age<<endl;

    cout<<”address:”<<addr<<endl;

    }

    private:

    int age; //新增加的數據成員

    string addr;

    };

    繼承方式包括:public公用的,private私有的和protected受保護的。C++默認為私有繼承。派生類會接收基類的所有成員,無法選擇。但是可以改變積累成員在派生類中的訪問屬性。也可以通過同名覆蓋來使新成員取代基類成員。

    1.3 派生類成員的訪問屬性

    C++奇淫技巧,程序員為啥天天學繼承與派生,真的有這麽難嗎
    不管是何種繼承方式,基類的私有成員只有基類的成員函數才可以引用,派生類的成員函數是無法引用的。即基類的私有成員是不可見的,它在被派生類繼承後變為不可訪問成員。

    不能通過派生類的對象引用從私有基類繼承過來的任何成員。派生類的成員函數不能訪問私有基類的私有成員,但可以訪問私有基類的公用成員。如何調用私有基類的公用成員函數如下:

    void Student::display_1()//輸出學號、姓名、分數、年紀和地址

    {

    display();//基類中的公用成員函數,目的是輸出學號、姓名和分數

    cout<<”age:”<<age<<endl;

    cout<<”address:”<<addr<<endl;

    }

    int main()

    {

    Student stud1;

    stud1.display();//在main中調用派生類中的公用成員函數

    return 0;

    }

    回顧:保護成員不能被類外訪問,類似於私有成員。但有一點與私有成員不同,保護成員可以被派生類的成員函數引用!如果希望在派生類中可以訪問基類的“私有”成員,則應當把它們聲明為保護成員。

    C++奇淫技巧,程序員為啥天天學繼承與派生,真的有這麽難嗎
    在派生類中引用保護成員

    #include<iostream>

    #include<string>

    using namespace std;

    class Student //聲明基類

    {

    public:

    void display();//基類共用成員函數

    protected:

    int num;//基類保護成員

    string name;

    char sex;

    };

    void Student::display()//定義基類成員函數

    {

    cout<<”num:”<<num<<endl;

    cout<<”name:”<<name<<endl;

    cout<<”sex:”<<sex<<endl;

    }

    class Student1: protected Student //用protected方式聲明派生類

    {

    public:

    void display1();//聲明派生類共用成員函數

    private:

    int age;//派生類私有數據成員

    string addr;

    };

    void Student1::display1()//定義派生類共用成員函數

    {

    display();

    cout<<”age:”<<age<<endl;

    cout<<”address:”<<addr<<endl;

    }

    int main()

    {

    Student1 stud1;

    stud1.display();//合法,stud1是派生類中的共用成員函數

    stud1.num=10023;//錯誤,外界不能訪問派生類的保護成員

    return 0;

    }

    1.4 派生類的構造函數與析構函數

    構造函數的主要作用是對數據成員進行初始化,且基類的構造函數是不能繼承的。對繼承過來的基類成員的初始化工作主要由派生類的構造函數承擔。

    一、簡單的派生類的構造函數

    簡單的派生類只有一個基類且只有一級派生,在派生類的數據稱成員中不包含基類的子對象。派生類構造函數首行的寫法格式:

    派生類構造函數名 (總參數列表): 基類構造函數名(參數列表)

    {派生類中新增數據成員初始化語句}

    Student1(int n,string nam,char s,int a,string ad):Student(n,nam,s)

    例 1.10.2簡單的派生類的構造函數

    #include<iostream>

    #include<string>

    using namespace std;

    class Student //聲明基類

    public:

    Student(int n,string nam,char s):num(n),name(nam),sex(s){}//基類構造函數

    ~Student(){} //基類析構函數

    protected:

    int num;

    string name;

    char sex;

    };

    class Student1: public Student //聲明派生類Student1

    {

    public:

    Student1(int n,string nam,char s,int a,string ad):Student(n,nam,s)

    //派生類構造函數

    {

    age=a;在函數體中僅對派生類新增的數據成員進行初始化

    addr=ad;

    }

    void show();

    private:

    int age;

    string addr;

    };

    void Student1::show()

    {

    cout<<”num:”<<num<<endl;

    cout<<”name:”<<name<<endl;

    cout<<”sex:”<<sex<<endl;

    cout<<”age:”<<age<<endl;

    cout<<address:”<<addr<<endl;

    }

    int main()

    {

    Student1 stud1(10010,”Wang li”,’f’,19,”115 Beijing Road, Shanghai”);

    Student1 stud2(10011.”Zhang fun”,’m’,21,”213 Shanghai Road, Beijing”);

    stud1.show();

    stud2.show();

    return 0;

    }

    實參首先傳給派生類構造函數的形參,然後派生類構造函數再將前面幾個傳遞給基類構造函數的形參。上例的具體過程見圖1.5。

    C++奇淫技巧,程序員為啥天天學繼承與派生,真的有這麽難嗎
    圖 1.5 參數傳遞過程

    在類內聲明派生類的構造函數,然後在類外定義派生類的構造函數

    class Student1: protected Student

    {

    public:

    Student1(int n,string nam,char s,int a,string ad);

    };

    Student1::Student1(int n,string nam,char s,int a,string ad):Student(n,nam,s)

    //定義時才給出基類構造函數名及其參數列表,聲明時不給出

    {

    age=a;

    addr=ad;

    }

    二、有子對象的派生類構造函數

    類的數據成員還可包含對象,稱為子對象。

    C++奇淫技巧,程序員為啥天天學繼承與派生,真的有這麽難嗎
    技術分享圖片
    格式:

    派生類構造函數名(總參數列表):基類構造函數名(參數列表),子對象名(參數列表)

    {派生類中新增加的數據成員初始化語句}

    Student1(intn,string nam,int n1,string nam1,int a,string ad): Student(n,nam),monitor(n1,nam1)

    執行派生類構造函數的順序:

    ① 調用基類構造函數,對基類數據成員初始化。

    ② 調用子對象構造函數,對子對象數據成員初始化。

    ③ 在執行派生類構造函數本身,對派生類數據成員初始化。

    在派生時,派生類是不能夠繼承基類的析構函數的,也需要通過派生類的析構函數去調用基類的析構函數。

    C++奇淫技巧,程序員為啥天天學繼承與派生,真的有這麽難嗎
    1.5 多重繼承

    一個派生類有2個或多個基類,派生類從2個或多個基類中繼承所需的屬性。如果已經聲明了類A和類B,則可以聲明多重繼承的派生類C:

    class C: public A, protected B

    {類C新增加的成員};

    一、多重繼承派生類的構造函數

    類似於單繼承,但是在初始表中包含多個基類構造函數。多重繼承派生類構造函數首行的寫法格式:

    派生類構造函數名(總參數列表):基類1構造函數(參數列表),基類2構造函數(參數列表)…

    {派生類中新增數據成員初始化語句}

    例 1.10.3聲明一個教師類和一個學生類,然後用多重繼承的方式聲明一個研究生類。教師類包括數據成員name,age和title(職稱)。學生類包括數據成員name1,sex和score。

    #include<iostream>

    #include<string>

    using namespace std;

    class Teacher //聲明類Teacher

    {

    public:

    Teacher(string nam,int a,string t):name(nam),age(a),title(t){}//構造函數初始化表

    void display();//輸出教師的數據

    protected:

    string name;

    int age;

    string title;

    };

    void Teacher::display()

    {

    cout<<”name:”<<name<<endl;

    cout<<”age:”<<age<<endl;

    cout<<”title:”<<title<<endl;

    }

    class Student //聲明類Student

    {

    public:

    Student(char nam[],char s,float sco)

    {

    strcpy(name1,nam);

    sex=s;

    score=sco;

    }

    void display1();

    protected:

    string name1;

    char sex;

    float score;

    };

    void Student::display1()

    {

    cout<<”name:”<<name1<<endl;

    cout<<”sex:”<<sex<<endl;

    cout<<”score:”<<score<<endl;

    }

    class Graduate: public Teacher,public Student //聲明多重繼承的派生類Graduate

    {

    public:

    Graduate(string nam,int a,char s,string t,float sco,float w): Teacher(nam,a,t), Student (nam, s, sco)

    {wage=w;}

    //多重繼承的派生類的構造函數

    void show();//輸出研究生有關數據

    private:

    float wage;//工資

    };

    void Graduate::show()

    {

    cout<<”name:”<<name<<endl;

    cout<<”age:”<<age<<endl;

    cout<<”sex:”<<sex<<endl;

    cout<<”score:”<<score<<endl;

    cout<<”title:”<<title<<endl;

    cout<<”wages:”<<wage<<endl;

    }

    int main()

    {

    Graduate grad1(“Wang li”,24,’f’,”assistant”,89.5,1234.5);

    grad1.show();

    return 0;

    }

    二、多重繼承引起的二義性問題

    繼承的成員同名會產生二義性問題。

    C++奇淫技巧,程序員為啥天天學繼承與派生,真的有這麽難嗎
    同名覆蓋:基類的同名成員在派生類中被屏蔽,成為不可見的,或者說,派生類新增加的同名成員覆蓋了基類中的同名成員。解決這種情況需要虛函數。

    如果類A和類B都是從一個基類派生的,情況如下圖1.6:

    C++奇淫技巧,程序員為啥天天學繼承與派生,真的有這麽難嗎
    圖 1.6 二義性問題的一種情況

    解決這種情況需要用到虛基類。

    1.6 虛基類

    一、虛基類的聲明

    由圖1.6可知,如果一個派生類有多個直接接類,而這些直接基類又有一個共同的基類,則在最終的派生類中會保留該間接共同基類數據成員的多份同名成員。為避免二義性,必須在派生類對象名後增加直接基類名,如c1.A::display()。C++提供虛基類的方法,使得在繼承間接共同基類時只保留一份成員。

    聲明虛基類的一般形式:

    class 派生類名: virtual 繼承方式 基類名

    Eg:

    class A //聲明基類A

    {……};

    class B: virtual public A //聲明類B是類A的共用派生類,A是B的虛基類

    {……};

    虛基類不是在聲明基類時聲明的,而是在聲明派生類時聲明的。virtual關鍵字不僅可以聲明虛基類,也用於聲明虛函數。在聲明派生類時,需要把virtual加到相應的繼承方式前面。經過這樣的聲明後,當基類通過多條派生路徑被一個派生類級城市,基類成員只保留一次。如圖1.7。

    C++奇淫技巧,程序員為啥天天學繼承與派生,真的有這麽難嗎
    圖 1.7 虛基類的情況

    為了保證虛基類在派生類中只被繼承一次,應當在該基類的所有直接派生類中聲明為虛基類,否則仍會出現對基類的多次繼承。

    二、虛基類的初始化

    C++奇淫技巧,程序員為啥天天學繼承與派生,真的有這麽難嗎
    由於虛基類在派生類中只有一份數據成員,所以這份數據成員的初始化必須由派生類直接給出。在最後的派生類中,不僅需要負責對直接基類進行初始化,也需要對虛基類進行初始化。

    例 1.10.4 在例1.10.3的基礎上,在教師類和學生類之上添加一個共同的基類Person。

    #include<iostream>

    #include<string>

    using namespace std;

    class Person //聲明公共基類Peroson

    {

    public:

    Person(string nam,char s,int a):name(name),sex(s),age(a){}//構造函數

    protected:

    string name;

    char sex;

    int age;

    };

    class Teacher:virtual public Teacher

    //聲明Person的直接派生類Teacher,且聲明Person為公用繼承的虛基類

    {

    public:

    Teacher(string nam,char s,int a,string t):Person(nam,s,a)//構造函數

    {title=t;}

    protected:

    string title;

    };

    class Student:virtual public Person

    //聲明Person的直接繼承類Student,且聲明Person為公用繼承的虛基類

    {

    public:

    Student(string nam,char s,int a,float sco):Person(nam,s,a)

    {score=sco;}

    protected:

    float score;

    };

    class Graduate: public Teacher,public Student //聲明多重繼承的派生類Graduate

    {

    public:

    Graduate(string nam,char s,int a,string t,float sco,float w):Person(nam,s,a),Teacher(name, s,a,t),Student(nam,s,a,sco) //在派生類中的構造函數,對直接基類和間接基類進行初始化

    {wage=w;}

    void show();

    private:

    float wage;

    };

    void Graduate::show()

    {

    cout<<”name:”<<name<<endl;

    cout<<”age:”<<age<<endl;

    cout<<”sex:”<<sex<<endl;

    cout<<”score:”<<score<<endl;

    cout<<”title:”<<title<<endl;

    cout<<”wages:”<<wage<<endl;

    }

    int main()

    {

    Graduate grad1(“Wang li”,’f’,24,”assistant”,89.5,1234.5);

    grad1.show();

    return 0;

    }

    C++奇淫技巧,程序員為啥天天學繼承與派生,真的有這麽難嗎