1.派生类的构造函数和析构函数
基类构造函数不能继承到派生类中
设计派生类的构造函数是需考虑的问题:
1.原有基类中数据成员的初始化
2.派生类中新增数据成员的初始化
3.解决思路:在派生类构造函数中,调用基类构造函数
#include<iostream>
#include<string>
using namespace std;
class student{ //定义一个父类student
protected:
string name;
int num;
date birth;
public:
student(string na,int nu);
void show();
};
student::student(string na,int nu):name(na),num(nu){ //此处为父类student的构造函数,利用参数列表的方法实现
}
void student::show(){ //定义父类的show函数
cout<<"name:"<<name<<endl<<"num:"<<num<<endl;
}
class student1:public student{ //从父类student继承下来一个子类student1
protected:
float score;
public:
student1(string na,int nu,float sc);
void show();
};
student1::student1(string na,int nu,float sc):student(na,nu),score(sc){
}//此处定义子类的构造函数,父类的构造函数必须写在这里 ,这样便可以在实现父类构造函数功能的同时写子类的构造函数成员
void student1::show(){
student::show(); //此处可以直接写上父类的作用域来实现代码的重用
cout<<"score:"<<score<<endl;
}
int main(){
student s("zhang",01);
s.show();
student1 s1("wang",02,90);
s1.show();
return 0;
}
name:zhang
num:1
name:wang
num:2
score:90 //此句便为子类构造函数加上的新变量
--------------------------------
Process exited after 2.729 seconds with return value 0
请按任意键继续. . .
倘若不满足于实现这些功能,用户需要增加一个出生年月日,并且要新定义一个date类,那么构造函数应该怎么写呢?
#include<iostream>
#include<string>
using namespace std;
class date{ //此处定义一个date类,用于存放学生的生日
private:
int year;
int month;
int day;
public:
void display(){
cout<<year<<"-"<<month<<"-"<<day<<endl;
}
date(int,int,int);
};
date::date(int y,int m,int d){
year = y;
month = m;
day = d;
}
class student{
protected:
string name;
int num;
date birth;
public:
student(string na,int nu,int y,int m,int d);
void show();
};
student::student(string na,int nu,int y,int m,int d):birth(y,m,d),name(na),num(nu){
}//注意:此处参数列表中对于生日的对象,直接用的是对象的名字,而不用类的名字!,
//前面的参数要一个一个的写上,不可以在前面参数中写date birth这类语句,只允许写每个小变量。
void student::show(){
cout<<"name:"<<name<<endl<<"num:"<<num<<endl;
cout<<"birthday:";
birth.display();
}
class student1:public student{
protected:
float score;
public:
student1(string na,int nu,int y,int m,int d,float sc);
void show();
};
student1::student1(string na,int nu,int y,int m,int d,float sc):student(na,nu,y,m,d),score(sc){
} //同样,子类的构造函数写的时候,只需要每个变量的值,不需要在:后面写birth,
//只需要将每个参数传入父类的构造函数中即可
void student1::show(){
student::show();
cout<<"score:"<<score<<endl;
}
int main(){
student s("zhang",01,2001,11,9);
s.show();
student1 s1("liu",02,2001,11,9,100);
s1.show();
return 0;
}
name:zhang
num:1
birthday:2001-11-9
name:liu
num:2
birthday:2001-11-9
score:100
--------------------------------
Process exited after 2.433 seconds with return value 0
请按任意键继续. . .
派生类构造函数的执行顺序
1.调用基类构造函数,对基类数据成员初始化
2.调用子对象构造函数,对子对象数据成员初始化
3.执行派生类构造函数本身,对派生类数据成员初始化
2.多层派生时的构造函数
多层派生时,不必列出每层的构造函数,仅需要调用派生类对应直接基类的构造函数
系统会自动的根据派生关系,层层调用对应的构造函数,实现对所有数据的初始化
若A的派生类是B,B的派生类是C,则C的构造函数仅调用直接基类B,B的构造函数调用直接基类A
调用顺序:调用B的构造函数,再调用A的构造函数,执行A函数体,执行B函数体,执行C函数体
3.派生类的析构函数
析构函数同样不能够被派生类继承
在派生类中定义自己的析构函数,并调用基类的析构函数
析构函数的调用顺序:
同构造函数相反,析构函数是从派生类开始执行,再调用基类的析构函数,执行基类内容的清理
- 多重继承
一个派生类有两个或多个基类
声明多重继承的方法
若已声明了类A,类B和类C,则可以声明派生类D如下:
class D: public A, private B,protected C
派生类D为多重继承,按指定的不同继承方式规则,分别从各个基类中继承数据成员和成员函数
与单继承构造函数类似,但在初始表中包含了多个基类的构造函数,中间用逗号隔开
格式:
派生类构造函数名(总参数列表): 基类1构造函数(参数列表), 基类2构造函数(参数列表), 基类3构造函数(参数列表)
{ 派生类中新增成员的初始化语句 }
5.多重继承引起的二义性问题
继承的数据成员和成员函数存在同名问题:
通过继承,得到了两个同名的数据成员或成员函数
为避免二义性,在使用时,利用作用域运算符,指出其所在的基类
合理的设计基类的成员,以尽量避免出现数据冗余
多重派生后,C类中数据的实际存储结构
若不指定数据所在作用域直接使用该成员,则根据靠近原则,调用派生类新定义的成员
若需要使用从基类继承的成员,则需指定基类作用域
一个例子:
假如一个人是在职研究生,他有两个身份:老师和学生,那么怎么通过多重继承来存放这个人的个人信息呢?
我们可以先这样写:
#include<iostream>
#include<string>
using namespace std;
class teacher{ //定义一个teacher类
protected:
string name;
int id;
public:
teacher(string,int);
void show();
};
teacher::teacher(string na, int i){
name = na;
id = i;
}
void teacher::show(){
cout<<"name:"<<name<<endl<<"id:"<<id<<endl;
}
class student{ //定义一个student类
protected:
string name;
int num;
public:
student(string,int);
void show();
};
student::student(string na,int nu){
name = na;
num = nu;
}
void student::show(){
cout<<"name:"<<name<<endl<<"num:"<<num<<endl;
}
/*
以下代码有一个问题:
那就是无论是teacher还是student,都有一个name数据成员
这就导致了,在子类初始化的时候,要初始化两个名字,这就不符合常理
*/
class zaizhi:public teacher,public student{ //通过多重继承,继承了来自teacher类和student类的数据成员
protected:
float score;
public:
zaizhi(string,int,string,int,float); //此处有两个string数据成员,分别代表两个名字
void show();
};
zaizhi :: zaizhi(string tn,int id,string sn,int nu,float sc):teacher(tn,id), student(sn,nu),score(sc){//此处有两个string数据成员,分别代表两个名字
}
void zaizhi::show(){
teacher::show();
student::show();
cout<<"score:"<<score<<endl;
}
int main(){
zaizhi a("zhang",1,"liu",1,99); //通过给两个name赋不一样的值,来说明这一问题
a.show();
}
name:zhang
id:1
name:liu
num:1
score:99
--------------------------------
Process exited after 6.906 seconds with return value 0
请按任意键继续. . .
可以看到,结果中出现了违背常理的数据,一个人怎么能有两个名字呢?
那么接下来,就要解决这个问题
我们可以尝试在构造函数的参数中减少一个name的数据成员,在构造函数给所有的数据成员赋初值的时候,将同一个字符串姓名同时赋给两个类的name成员,便可解决这一问题
#include<iostream>
#include<string>
using namespace std;
class teacher{
protected:
string name;
int id;
public:
teacher(string,int);
void show();
};
teacher::teacher(string na, int i){
name = na;
id = i;
}
void teacher::show(){
cout<<"name"<<name<<"id"<<id<<endl;
}
class student{
protected:
string name;
int num;
public:
student(string,int);
void show();
};
student::student(string na,int nu){
name = na;
num = nu;
}
void student::show(){
cout<<"name"<<name<<"num"<<num<<endl;
}
class zaizhi:public teacher,public student{
protected:
float score;
public:
zaizhi(string,int,int,float); //注意,此处在定义构造函数时故意减少了一个string变量
void show();
};
zaizhi :: zaizhi(string tn,int id,int nu,float sc):teacher(tn,id), student(tn,nu),score(sc){
}//由于上面减少了一个string变量,那么,就可以将一个string分别赋值给两个name变量,实现统一(两个tn)
void zaizhi::show(){
teacher::show();
student::show();
cout<<"score"<<score<<endl;
}
int main(){
zaizhi a("zhang",1,1,99); //“zhang”这个字符串分别赋值给了student和teacher的name变量
a.show();
}
name:zhang:
id:1
name:zhang:
num:1
score:99
--------------------------------
Process exited after 2.357 seconds with return value 0
请按任意键继续. . .
结果显示,两个name均变成了zhang
解决了这一问题