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