C++57个入门知识点_27 继承的概念(类的组合关系:将一个类的对象作为另外一个类的成员;类的组合关系的访问;继承的概念:A类是B的儿子;A被称为子类,B被称为父类或者A被称为派生类,B被称为基类)

我们知道类有三大特性:封装、继承和多态。封装在前面已经介绍完。本篇开始将会介绍继承。继承是在封装基础上的扩展,也是多态的一个承接。

总结:

  1. 类的组合关系:将一个类的对象作为另外一个类的成员 Class CStudent{ ... public:/private: CPerson m_Per ... }
  2. 类的组合关系的访问方法
  • 类对象放到public进行访问,使用stu.m_per.SetGender(123);的方式访问
  • 类对象放到private,使用公共访问权限的函数进行访问:stu.SetGender(123);
  1. 继承:一个类可以继承另外一个类中的东西,即为继承。
  • 继承的概念:A类是B的儿子
  • A被称为子类,B被称为父类或者A被称为派生类,B被称为基类
  • 关系:子类 is-a 父类 (子类是一个父类的…,学生是一个人)
  • 代码形式为:class CStudent :public CPerson

1. 学生管理系统的传统写法

以一个学生管理系统为例,按照之前的思路,需要创建不同的类,然后将类组合在一起

创建学生类,老师类,这两个类都是有姓名和性别的成员变量,此时就造成了冗余,易造成错误,可能让人嗅到坏坏的味道。

其代码如下:

#include <iostream>

//面向对象:继承
//学生与老师具有人的共有特征

class CStudent {
public:
	CStudent() {
	}

	~CStudent() {
	}

	int GetGender() {
	return m_nGender;
	}

	void SetGender(int nGender) {
		m_nGender= nGender;
	}
private:
	char m_nszName[255];
	int m_nGender;
};

//增加老师管理系统,老师的数据与行为和学生是类似的,但也有学号,老师号的不同
//如果重建一个老师类就会造成冗余,易造成错误
class CTeacher {
public:
	CTeacher() {
	}
	~CTeacher() {
	}

	int GetGender() {
		return m_nGender;
	}

	void SetGender(int nGender) {
		m_nGender = nGender;
	}

private:
	char m_nszName[255];
	int m_nGender;
};

int main(int argc, char* argv[])
{
	CStudent stu;
	return 0;
}

除了学生和老师类,如果需要再增加宿管阿姨的信息,那就得再创建一个类,同样的代码会反复出现,可能就带来问题,如果同类型的一个地方出错,就需要在代码不同位置修改,十分不利于程序编写。

2. 类的组合关系

将一个类的对象作为另外一个类的成员这种关系称之为 类的组合关系

针对上面的问题,如何解决?
解决思路,出现上面的问题的原因是:代码出现了重复,这是因为学生和老师存在共同的部分。
但是除了共性部分,学生可能有学生ID m_nStuID,老师有老师ID m_nTeaID对于相同的代码我们使用代码去描述,不同的地方加以区别

学生和老师共有人的特征(名字和性别),因此将其 重复共有的部分单独提取 出来写出一个人类。将人作为学生和老师类的属性和特点-将一个类的对象作为另外一个类的成员这种关系称之为 类的组合关系

类的组合关系的访问方法

  • 类对象放到public进行访问,使用stu.m_per.SetGender(123);的方式访问
#include <iostream>
class CPerson
{

public:
	CPerson() {
	}

	~CPerson() {
	}

	int GetGender() {
		return m_nGender;
	}

	void SetGender(int nGender) {
		m_nGender = nGender;
	}

private:
	char m_nszName[255];
	int m_nGender;
};

class CStudent {
public:
	CStudent() {
	}
	~CStudent() {
	}
	
	CPerson m_per;//组合关系:将一个类的成员作为另一个类的成员(共用人的共性)
	
private:
	int m_nStuID;
};

//增加老师管理系统,老师的数据与行为和学生是类似的,但也有学号,老师号的不同
//如果重建一个老师类就会造成冗余,易造成错误
class CTeacher {
public:
	CTeacher() {
	}
	~CTeacher() {
	}
	
	CPerson m_per;//组合关系:将一个类的成员作为另一个类的成员(共用人的共性)
	
private:
	int m_nTeaID;
};


int main(int argc, char* argv[])
{
	CStudent stu;
	stu.m_per.SetGender(123);	
	return 0;
}
  • 类对象放到private,使用公共访问权限的函数进行访问:stu.SetGender(123);
#include <iostream>

class CPerson
{
public:
	CPerson() {
	}

	~CPerson() {
	}

	int GetGender() {
		return m_nGender;
	}

	void SetGender(int nGender) {
		m_nGender = nGender;
	}

private:
	char m_nszName[255];
	int m_nGender;
};

class CStudent {
public:
	CStudent() {
	}

	~CStudent() {
	}

	void SetGender(int nGender) {

		m_per.SetGender(nGender);
	}

private:
	CPerson m_per;//组合关系:将一个类的成员作为另一个类的成员(共用人的共性)
	int m_nStuID;
};

//增加老师管理系统,老师的数据与行为和学生是类似的,但也有学号,老师号的不同
//如果重建一个老师类就会造成冗余,易造成错误
class CTeacher {
public:
	CTeacher() {
	}

	~CTeacher() {
	}

private:
	CPerson m_per;//组合关系:将一个类的成员作为另一个类的成员(共用人的共性)
	int m_nTeaID;
};

int main(int argc, char* argv[])
{

	CStudent stu;
	stu.SetGender(123);
	return 0;
}

上面的过程虽然一定程度上实现了公共属性的复用,只是将关系进行了简单的组合,还是有些繁琐。

2.1 类的组合关系中内存释放问题

首先我们需要了解,如果是栈上的对象,出作用域编译器会自动调用析构函数,并进行内存释放,但是这里的内存释放,不是说立马就将内存中的数据进行销毁,而是将改内存空间标记为不可用,后期会重新分配使用,以下是我用基本数据类型进行的实验。
在这里插入图片描述
int a原先所占的栈空间,在出{}作用域之后,数据并没有立刻销毁。

说这个是为了演示上面CStudent stu;和组合对象CPerson m_per;都是创建在栈上的,那么出作用域之后也会自动调用析构函数,并进行内存释放,但是像上面所说 “不是说立马就将内存中的数据进行销毁,而是将改内存空间标记为不可用,后期会重新分配使用”,演示结果如下:
在这里插入图片描述
如果CStudent类的对象是创建在堆上,而组合对象CPerson m_per;是创建在栈上的,再进行析构的时候会是什么样的结果呢?
在这里插入图片描述
可以看到CPerson m_per;中的空间也是会自动销毁,并且看起来是立即生效的,理解这个对以后创建组合关系是很有用处的。
上面在做delete stu之后,应该要改为以下代码,否则会创造出野指针,也就是内存释放了,但是stu指向的确实一个无效内存。

if (nullptr==stu)
{
	delete stu;
	stu = nullptr;
}

3. 类的继承

为了使得重复属性的使用更为简单,提出了继承的语法

继承的性质:

  • 继承的概念:A类是B的儿子

  • A被称为子类,B被称为父类或者A被称为派生类,B被称为基类

  • 关系:子类 is-a 父类 (子类是一个父类的…,学生是一个人)
    在这里插入图片描述

  • 代码形式为:class CStudent :public CPerson

#include <iostream>

//面向对象:继承
//学生与老师具有人的共有特征

class CPerson
{

public:
	CPerson() {
	}

	~CPerson() {
	}

	int GetGender() {
		return m_nGender;
	}

	void SetGender(int nGender) {
		m_nGender = nGender;
	}

private:
	char m_nszName[255];
	int m_nGender;
};

class CStudent : public CPerson
{
public:
	CStudent() {
	}
	~CStudent() {
	}

private:
	int m_nStuID;
};

class CTeacher : public CPerson
{
public:
	CTeacher() {
	}
	~CTeacher() {
	}

private:
	int m_nTeaID;
};


int main(int argc, char* argv[])
{

	CStudent stu;
	stu.SetGender(123);
	return 0;
}

运行结果:stu对象调用了父类CPerson中的成员函数
在这里插入图片描述
在这里插入图片描述

4.学习视频地址:C++57个入门知识点_27 继承的概念

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十月旧城

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值