[C++]学习笔记7:继承与派生(2)

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.派生类的析构函数
析构函数同样不能够被派生类继承
在派生类中定义自己的析构函数,并调用基类的析构函数

析构函数的调用顺序:
同构造函数相反,析构函数是从派生类开始执行,再调用基类的析构函数,执行基类内容的清理

  1. 多重继承
    一个派生类有两个或多个基类

声明多重继承的方法
若已声明了类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
解决了这一问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值