C++面向对象程序设计 - 派生类的构造函数和析构函数

文章详细讲述了派生类构造函数如何调用基类构造函数初始化数据成员,以及在包含子对象的情况下如何处理构造和析构顺序,强调了资源在正确顺序下释放的重要性。
摘要由CSDN通过智能技术生成

        构造函数的主要作用对数据成员初始化,基类的构造函数是不能被继承的,在声明派生类时,派生类并没有把类的构造函数继承下来。因此,对继承过来的基类成员初始化的工作也要由派生类的构造函数完成;所以在派生类中不仅要考虑自身增加的数据成员的初始化,还要考虑基类的数据成员的初始化。

一、派生类的构造函数

        解决方法则是,在执行派生类的构造函数时,调用基类的构造函数。

        其一般形式为

派生类构造函数名 ( 总参数表列 ) : 基类构造函数名 ( 参数表列 ) 

{

        派生类中新增数据成员初始化语句

}

        这里通过人与学生类示例来演示,将Person类数据成员设置为保护成员,这样方便直接在派生类中调用。代码如下:

#include <iostream>
#include <string>
using namespace std;
// 基类 - 人类
class Person{
	protected:
		string name;	// 姓名
		int age;		//年龄
		char gender;	//性别
	public:
		Person(){
			name = "anonym";
			age = 0;
			gender = 0;
		}
		Person(string name, int age, char gender): name(name), age(age), gender(gender){}
};
// 派生类 - 学生
class Student: public Person{
	private:
		string school;
	public:
		Student(string name, int age, char gender, string school): Person(name, age, gender){
			this->school = school;
		}
		void display(){
			cout <<"name:" <<name <<endl;
			cout <<"age:" <<age <<endl;
			cout <<"gender:" <<(gender=='1'?"male":"female") <<endl;
			cout <<"school:" <<school <<endl;
		}
};
int main(){
	Student s("Tom", 18, '1', "middle school");
	s.display();
	return 0;
}

        运行结果如下:

在建立一个对象时,执行构造函数的顺序:

  1. 派生类构造函数先调用基类构造函数;
  2. 再执行派生类构造函数本身(即派生类构造函数的函数体)。

二、有子对象的派生类的构造函数

        在类对象中,数据成员都是标准类型(如int,char)或系统提供的类型(如string),但实际上,类的数据成员中还可以包含类对象。类对象中内嵌对象,即对象中的对象,称为子对象。

        这里将学生对应的班长,先以Person类表示,在Student类中定义子对象并在派生类构造函数中初始化。代码如下:

#include <iostream>
#include <string>
using namespace std;
// 基类 - 人类
class Person{
	protected:
		string name;	// 姓名
		int age;		//年龄
		char gender;	//性别
	public:
		Person(){
			name = "anonym";
			age = 0;
			gender = 0;
		}
		Person(string name, int age, char gender): name(name), age(age), gender(gender){}
		void display(){
			cout <<"name:" <<name <<endl;
			cout <<"age:" <<age <<endl;
			cout <<"gender:" <<(gender=='1'?"male":"female") <<endl;
		}
};
// 派生类 - 学生
class Student: public Person{
	private:
		Person monitor;		// 定义子对象(班长)
		string school;
	public:
		// 构造函数,并初始化基类和子对象
		Student(string name, int age, char gender, string school, string m_name, int m_age, char m_gender): 
			Person(name, age, gender), school(school), monitor(m_name, m_age, m_gender){}
		void display(){
			cout <<"name:" <<name <<endl;
			cout <<"age:" <<age <<endl;
			cout <<"gender:" <<(gender=='1'?"male":"female") <<endl;
			cout <<"school:" <<school <<endl;
			
			cout <<endl <<"monitor:" <<endl;
			monitor.display();
		}
};
int main(){
	Student s("Tom", 18, '1', "middle school", "John", 19, '1');
	s.display();
	return 0;
}

        运行结果如下:

        派生类构造函数的任务包括三部分:

  1. 对基类数据成员初始化;
  2. 对子对象数据成员初始化;
  3. 对派生类数据成员初始化。

        定义派生类构造函数的一般形式:

派生类构造函数名 (总参数表列) : 基类构造函数名 (参数表列), 子对象名 (参数表列)

{

        派生类中新增数据成员初始化语句

}

        执行派生类构造函数的顺序:

  1. 调用基类构造函数,对基类数据成员初始化;
  2. 调用子对象构造函数,对子对象数据成员初始化;
  3. 再执行派生类构造函数本身,对派生类数据成员初始化。

三、多层派生时的构造函数

        一个类不仅可以派生出一个派生类,派生类还可以继续派生,形成派生的层次结构。

        这里在Person类和Student类基础上再定义一个Teacher类,其顺序是Person -> Student -> Teacher。示例代码如下:

#include <iostream>
#include <string>
using namespace std;
// 基类 - 人类
class Person{
	protected:
		string name;	// 姓名
		int age;		//年龄
		char gender;	//性别
	public:
		Person(){
			name = "anonym";
			age = 0;
			gender = 0;
		}
		Person(string name, int age, char gender): name(name), age(age), gender(gender){}
};
// 派生类 - 学生
class Student: public Person{
	private:
		string school;
	public:
		// 构造函数,并初始化基类
		Student(string name, int age, char gender, string school): 
			Person(name, age, gender), school(school){}
		string show_school(){
			return school;
		}
		void display(){
			cout <<"name:" <<name <<endl;
			cout <<"age:" <<age <<endl;
			cout <<"gender:" <<(gender=='1'?"male":"female") <<endl;
			cout <<"school:" <<school <<endl;
			cout <<endl;
		}
};
class Teacher: public Student{
	private:
		string course;			//课程
	public:
		// 构造函数,并初始化基类
		Teacher(string name, int age, char gender, string school, string course): 
			Student(name, age, gender, school), course(course){}
		void display(){
			cout <<"name:" <<name <<endl;
			cout <<"age:" <<age <<endl;
			cout <<"gender:" <<(gender=='1'?"male":"female") <<endl;
			cout <<"school:" <<show_school() <<endl;
			cout <<"course:" <<course <<endl;
			cout <<endl;
		}
};
int main(){
	Student s("Tom", 18, '1', "middle school");		//定义学生类对象
	Teacher t("Lily", 30, '2', "middle school", "Mathematics");	//定义教师类对象
	
	s.display();	// 显示学生信息
	t.display();	//显示教师信息
	return 0;
}

        运行结果如下:

        初始化顺序:

  1. 先初始化基类(Person)的数据成员;
  2. 再初始化派生类(Student)的数据成员;
  3. 最后再初始化派生类(Teacher)的数据成员。

四、派生类的析构函数

        析构函数的作用是在对象撤销之前,进行必要的清理工作。当对象被删除时,系统会自动调用析构函数。

        在派生类中析构函数不能被继承,也需要通过派生类的析构函数去调用基类的析构函数。在派生类中可以根据需要定义析构函数,用来对派生类中所增加的成员进行清理工作,基类的清理工作扔然由基类的析构函数完成。在执行派生类的析构函数时,系统会自动调用基类的析构函数和子对象的析构函数,对基类和子对象进行清理。

        析构函数的调用顺序刚好与构造函数相反,析构函数是先调用派生类的析构函数,对派生类的成员进行清理,然后调用子对象的析构函数对子对象进行清理,最后调用基类的析构函数对基类进行清理。

        这里将子对象中代码稍作修改,来演示析构函数执行顺序,示例代码如下:

#include <iostream>
#include <string>
using namespace std;
// 基类 - 人类
class Person{
	protected:
		string name;	// 姓名
		int age;		//年龄
		char gender;	//性别
	public:
		Person(){
			name = "anonym";
			age = 0;
			gender = 0;
		}
		Person(string name, int age, char gender): name(name), age(age), gender(gender){}
		// 基类的析构函数
		~Person(){
			cout <<name <<", Person constructor" <<endl;
		}
};
// 派生类 - 学生
class Student: public Person{
	private:
		Person monitor;		// 定义子对象(班长)
		string school;
	public:
		// 构造函数,并初始化基类和子对象
		Student(string name, int age, char gender, string school, string m_name, int m_age, char m_gender): 
			Person(name, age, gender), school(school), monitor(m_name, m_age, m_gender){}
		// 派生类的析构函数
		~Student(){
			cout <<name <<", Student constructor" <<endl;
		}
};
int main(){
	Student s("Tom", 18, '1', "middle school", "John", 19, '1');
	return 0;
}

        运行结果如下:

        由图可见,基类(Person类)是最后执行的,子对象(John对象)是在基类之前执行,而最先执行的则是派生类(Student类)。

        这个过程是确保了资源在正确的顺序中被释放。

  • 33
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值