c++派生類與繼承

派生類的構造函數和析構函數
基類的構造函數和析構函數不能被繼承,在派生類中,若是對派生類新增的成員進行初始化,須要加入派生類的構造函數
當派生類建立對象時,首先執行基類的構造函數,隨後執行派生類的構造函數;當撤銷派生類對象時,先執行派生類的析構函數,在執行基類的析構函數。
當基類的構造函數沒有參數或沒有顯式定義構造函數時,派生類能夠不向基類傳遞參數,甚至能夠不定義構造函數。ios

#include<iostream>
#include<string>
using namespace std;
class student
{
    public:
    student(int number1,string name1,float score1)
    {
        number=number1;
        name=name1;
        score=score1;
        }   
    void print()
    {
        cout<<"number:"<<number<<",name"<<name<<",score"<<score<<endl;
    }
    protected:
        string name;
        int number;
        float score;
};
class ustudent:public student
{
        public:
            ustudent(int number1,string name1,float score1,string major1):student(number1,name1,score1)//定義派生類構造函數時,綴上要調用的基類的構造函數及其參數 
            {
                major=major1;
            }
            void print1()
            {
                print();
                cout<<"major:"<<major<<endl;
            }
            protected:
                string major;
};
int main()
{
    ustudent stu(1234,"zhangsan",89,"英語");
    stu.print1();
    return 0;
}

冒號前面時派生類構造函數的主幹,冒號後面是調用的基類構造函數及其參數。總參數列表包括基類構造函數所需的參數和派生類新增的數據成員初始化所須要的參數。
當基類構造函數不帶參數時,派生類不必定須要定義構造函數,然而當基類構造函數哪怕只是帶有一個參數,他全部的派生類都必須定義構造函數,甚至所定義的派生類構造函數可能爲空,僅僅起參數傳遞的做用。
如:web


class base
{
public:
base(int n)
{
cout<<"基類"<<endl;
i=n;
}
private:
int i;
} ;
class deprived:public base
{
public:
deprived(int n):base(n)
{
}
};
派生類構造函數列表只有一個參數,傳遞給了要調用的基類構造函數base,派生類構造函數體爲空。svg

在定義派生類對象時,構造函數的執行順序以下:
1.調用基類的構造函數,對基類數據成員初始化
2.調用內嵌對象成員的構造函數,對內嵌對象成員的數據初始化;
3.執行派生類的構造函數體,對派生類數據成員初始化。
撤銷對象時,析構函數的調用順序與構造函數的調用順序正好相反。函數

#include<iostream>
#include<string>
using namespace std;
class student
{
    public:
        student(int number1,string name1,float score1)
        {
            number=number1;
            name=name1;
            score=score1;
        }
        void print()
        {
            cout<<"學號:"<<number<<endl;
            cout<<"姓名:"<<name<<endl;
            cout<<"成績:"<<score<<endl;
        }
        protected:
            int number;
            string name;
            float score;
 };

 class ustudent:public student{
    public:
        ustudent(int number1,string name1,float score1,int number2,string name2,float score2,int number3,string name3,float score3,string major1):student(number1,name1,score1),auditor3(number3,name3,score3),auditor2(number2,name2,score2)
        {
            major=major1;
         }
         void print()
         {
            cout<<"正式生是:"<<endl;
            student::print();
            cout<<"專業:"<<major<<endl;
         }
         void print_auditor3()
         {
            cout<<"旁聽生是:"<<endl;
            auditor3.print();
         }
         void print_auditor2()
         {
            cout<<"旁聽生是:"<<endl;
            auditor2.print();
         }
         private:
            string major;
            student auditor2;
            student auditor3;
 };

 int  main()
 {
    ustudent stu(2001,"張三",89,3001,"王五",90,3002,"李四",99,"數學");
     stu.print();
     stu.print_auditor2();
     stu.print_auditor3();

     return 0;
 }

運行結果:
正式生是:
學號:2001
姓名:張三
成績:89
專業:數學
旁聽生是:
學號:3001
姓名:王五
成績:90
旁聽生是:
學號:3002
姓名:李四
成績:99ui

在派生類中含有多個內嵌對象成員時,調用內嵌對象成員的構造函數順序由他的順序肯定們在類中聲明
在上述代碼中,有兩個內嵌對象成員auditor2,auditor3,,儘管在派生類構造函數中,auditor2的構造函數寫在auditor3的後面,可是調用順序仍是先執行auditor2,後執行auditor3,由於調用內嵌對象成員的構造函數順序由他們在類中的聲明順序肯定。spa

在派生類中使用基類的同名成員
使用以前加上基類名和做用域標識符「::」code

class X
{
    public :
        int f();
};
class Y:public X
{
    publicint f();
    int g(); 
};
void Y::g()
{
    f();//表示訪問的是派生類中的f(),即調用Y::f();
    X::f();//要訪問基類中的f(),則如此表示 
}

//派生類對象訪問時 
Y obj;
obj.f(); 
obj.X::f();//要訪問基類中的f() 

又如:xml

include

using namespace std;
class student
{
public:
student(int number1,string name1,float score1)
{
number=number1;
name=name1;
score=score1;
}
void print()
{
cout<<」number:」<對象

#include<iostream>
using namespace std;
class A
{
    public:
        A(int x1)
        {
            x=x1;
        }
        void print()
        {
            cout<<"x:"<<x<<endl;
        }
        private:
            int x;
};

class B:private A
{
    public:
        B(int x1,int y1):A(x1)
        {
            y=y1;
        }
        A::print;//B私有繼承A,則print()方法也變爲私有,此操做能夠將私有變爲共有 
        //A::print()爲錯誤寫法 
        private:
            int y;
};

int main()
{
    B b(10,20);
    b.print();
    return 0;
 }

訪問聲明不能改變成員在基類中的訪問屬性,即訪問聲明只能把原基類的保護成員調整爲私有派生類的保護成員,把原基類的公有成員調整爲私有派生類的公有成員,但對基類的私有成員不能使用訪問聲明繼承

多重繼承

#include<iostream>
using namespace std;
class X
{
    public:
        X(int sa)
        {
            a=sa;
            cout<<"執行X的構造函數"<<endl;
        }
        int getX()
        {
            return a;
        }
        ~X()
        {
            cout<<"X的析構函數"<<endl;
        }
        private:
            int a;
};

class Y
{
    public:
        Y(int sb)
        {
            b=sb;
            cout<<"執行X的構造函數"<<endl;
        }
        int getY()
        {
            return b;
        }
        ~Y()
        {
            cout<<"Y的析構函數"<<endl;
        }
        private:
            int b;
};
class Z:public X,private Y
{
    public:
        Z(int sa,int sb,int sc):X(sa),Y(sb)//類 Z爲基類XY的派生類,冒號後面指把sa傳遞給X的構造函數,sb傳遞給Y的構造函數
        //這樣Z建立對象時,他的構造函數會自動地用參數表中的數據調用基類額構造函數,完成基類對象的初始化 
        {
            c=sc;
            cout<<"執行X的構造函數"<<endl;
        }
        int getZ()
        {
            return c;
        }
        int getY()
        {
            Y::getY();
        }
        ~Z()
        {
            cout<<"Z的析構函數"<<endl;
        }
        private:
            int c;
};

int main()
{
    Z obj(1,2,3);
    int ma=obj.getX();
    cout<<"a:"<<ma<<endl;
    int mb=obj.getY();//調用的是Z的getY,不是Y的getY 
    cout<<"b:"<<mb<<endl;
    int mc=obj.getZ();
    cout<<"c:"<<mc<<endl;
    return 0;
}

結果:
執行X的構造函數
執行Y的構造函數
執行Z的構造函數
a:1
b:2
c:3
Z的析構函數
Y的析構函數
X的析構函數

多重繼承的構造函數執行順序與單繼承構造函數的執行順序相同,析構函數與構造函數執行順序相反。

虛基類

當基類經過多條派生路徑被一個派生類繼承時,該派生類只繼承該基類一次,也就是說,基類只保留一次

#include<iostream>
using namespace std;
class base
{
    public:
        base()
        {
            a=5;
            cout<<"base a="<<a<<endl;
        }
        protected:
            int a;
};

class base1:virtual public base
{
    public:
        int b1;
        base1()
        {
            a=a+10;
            cout<<"base1 a="<<a<<endl;
        }
};

class base2:virtual public base
{
    public:
        int b2;
        base2()
        {
            a=a+20;
            cout<<"base2 a="<<a<<endl;
        }
};

class deprived:public base1,public base2
{
    public:
        int d;
        deprived()
        {
            cout<<"deprived a="<<a<<endl;
        }
};
int main()
{
    deprived obj;
    return 0;
}

結果:
base a=5
base1 a=15
base2 a=35//通過base後,a變爲15,因此base2進行操做加20時,直接15+20,最終爲35
deprived a=35

虛基類的初始化:
1.若是在虛基類中定義帶有形參的構造函數,而且沒有定義默認形式的構造函數,則整個繼承結構中,全部直接或間接的派生類都必須在構造函數的成員初始化列表中列出對虛基類構造函數的調用,以初始化在虛基類中定義的數據成員
2.創建一個對象時,若是這個對象中含有從虛基類繼承來的成員,則虛基類的成員時由最遠派生類的構造函數經過調用虛基類的構造函數進行初始化的,該派生類的其餘基類對虛基類構造函數的調用自動忽略。
3.在同一層次同時包含虛基類和非虛基類時,應先調用虛基類的構造函數,再調用非虛基類的構造函數,最後調用派生類的構造函數
4.若虛基類由非虛基類派生而來,則先調用基類構造函數,再調用派生類的構造函數。

#include<iostream>
using namespace std;
class base
{
    public:
        base(int sa)
        {
            a=sa;
            cout<<"constructing base"<<endl;
        }
        private:
            int a;
};
class base1:virtual public base
{
    public:
        base1(int sa,int sb):base(sa)
        {
            b=sb;
            cout<<"constructing base1"<<endl;
        }
        private:
            int b;
};
class base2:virtual public base
{
    public:
        base2(int sa,int sc):base(sa)
        {
            c=sc;
            cout<<"constructing base2"<<endl;
        }
        private:
            int c;
};
class deprived:virtual base1,base2
{
    public:
        deprived(int sa,int sb,int sc,int sd):base(sa),base1(sa,sb),base2(sa,sc)
        {
            d=sd;
            cout<<"constructing deprived"<<endl;
        }
        private:
            int d;
};

int main()
{
    deprived obj(1,2,3,4);
    return 0;
}

結果:
constructing base
constructing base1
constructing base2
constructing deprived

若base2繼承base時base不是虛基類,則:
constructing base
constructing base1
constructing base
constructing base2
constructing deprived
因此,當base時虛基類時,base的構造函數只執行一次,當deprived的構造函數調用了虛基類base的構造函數後,類base1,base2構造函數的調用被忽略。

虛基類的簡單應用
data_rec時虛基類,包含全部派生類共有的數據成員,職工類employee和學生類student爲Data_rec的派生類,職業類大學生E_student是職工類和學生類的共同派生類

#include<iostream>
#include<string>
using namespace std;
class data_rec
{
    public:
        data_rec(string name1,char sex1,int age1)
        {
            name=name1;
            sex=sex1;
            age=age1;
        }
        protected:
            string name;
            char sex;
            int age;
};

class student:virtual public data_rec
{
    public:
        student(string name1,char sex1,int age1,string major1,double score1):data_rec(name1,sex1,age1)
        {
            major=major1;
            score=score1;
        }
        protected:
            string major;
            double score;
};
class employee:virtual public data_rec
{
    protected:
        string dept;//部門 
        double salary;//薪水 
        public:
            employee(string name1,char sex1,int age1,string dept1,double salary1):data_rec(name1,sex1,age1)
            {
                dept=dept1;
                salary=salary1;
            }
};

class E_student:public student,public employee
{
    public:
        E_student(string name1,char sex1,int age1,string major1,double score1,string dept1,double salary1):data_rec(name1,sex1,age1),student(name1,sex1,age1,major1,score1),employee(name1,sex1,age1,dept1,salary1)
        {

        }
        void print()
        {
            cout<<"name:"<<name<<endl;
            cout<<"sex:"<<sex<<endl;
            cout<<"age:"<<age<<endl;
            cout<<"major:"<<major<<endl;
            cout<<"score:"<<score<<endl;
            cout<<"dept:"<<dept<<endl;
            cout<<"salary:"<<salary<<endl;
        }
};
int main()
{
    E_student e_stu("張三",'m',23,"計算機",99,"教務處",3000);
    e_stu.print();
    return 0;
}

結果: name:張三 sex:m age:23 major:計算機 score:99 dept:教務處 salary:3000