Bootstrap

C++_基本语法笔记_继承和多态

继承

思想与Java差不多

基本语法

  • 语法:class 子类 : 继承方式 父类
    在这里插入图片描述

继承方式

  • 将访问权限,上升到保护权限,上升到更高的私有权限
    在这里插入图片描述

继承哪些部分

  • 继承过程中,即使权限不能访问,也会全部继承下来(非静态属性是共有的,不会继承)

在这里插入图片描述

构造和析构顺序

    1. 先构造父类
    1. 构造子类
    1. 析构子类
    1. 析构父类

子类和父类出现同名成员

若子类和父类,有相同名字的成员(属性/方法)。

  • 加作用域就完事

在这里插入图片描述

  • 同名属性值:
    在这里插入图片描述在这里插入图片描述
  • 同名函数:
    在这里插入图片描述
  • 无论是属性还是方法,都会优先用子类的,即使重载才有可能溯源到父类

子类和父类出现同名成员(静态)

处理方式一致
在这里插入图片描述

  • 访问方式:
  • 直接访问子类;
  • 通过子类访问父类。
    在这里插入图片描述

多继承(一个类继承多个类)

语法: class 子类 : 继承方式 父类1 , 继承方式 父类2...。如果有同名成员出现,加作用域区分。

  • 两个父类有相同属性值:
    在这里插入图片描述
  • 使用方式:
    在这里插入图片描述

菱形继承

在这里插入图片描述一些问题:
在这里插入图片描述
解决:

在这里插入图片描述在这里插入图片描述

  • 虚继承:子类在继承父类时,加上关键字 virtual。
  • 下面的 sheep 和 tuo 都在虚拟继承Animal类。这时,Animal类被称为 虚基类

在这里插入图片描述

  • 虚继承就是使用虚类指针 指向 虚类表,多个子类共享继承的成员,不会混乱
    在这里插入图片描述
  • 虚基类的底层:
    在这里插入图片描述

再举个例子:
在这里插入图片描述

  • 下面来用存储结构说明一下:

  • 左边是非虚继承,A类继承了2个 int a 的值。

  • 右边是虚继承,只有一份 int a 的值,两个virtual继承的子类B和C,其实不是真的继承,只是用表指向共有的a值

在这里插入图片描述

多态

基本用法

在这里插入图片描述

  • 小贴士:静态绑定在程序运行中不可更改,记住这个

  • 在下面准备两个类,都有speak方法

在这里插入图片描述没有产生希望的 ”小猫在说话”:

  • 形参这里Animal &animal等同于 Animal & animal = cat
  • 函数内animal.speak应该是:小猫 才对。但是因为草绑定,绑定的是父类Animal类。

在这里插入图片描述

解决方式:虚函数。可以实现地址晚绑定,从而实现动态多态

  • 虚函数speak写在父类里,直到确认某个对象,才绑定地址
  • virtual允许父子类之间的函数重载(重写也行)

在这里插入图片描述
多态条件:

  1. 有继承
  2. 子类要重写从父类继承来的虚函数(类似Java的抽象函数强制重写)

使用条 件:

  1. 参数:父类的指针/引用,执行子类对象

多态内部原理

  • 父类和子类都有虚函数表

  • 虚函数表内部记录当前作用域中虚函数(speak)的地址

  • 当子类重写父类的虚函数,子类的虚函数表中内容就会被覆盖

  • 多态的关键是虚函数指针和虚函数表

在这里插入图片描述

抽象类

父类:抽象计算器
子类:加/减/乘/除法计算器

多态:getResult声明为虚函数,期待各种子类重写
在这里插入图片描述多态方便维护某个加/减/乘/除计算器

在这里插入图片描述

纯虚函数 抽象类

和Java很像:在父类中声明纯虚函数,强制子类重写该函数。有纯虚函数的类叫抽象类,不能实例对象。
在这里插入图片描述在这里插入图片描述

多态案例

在这里插入图片描述
定义抽象类:
在这里插入图片描述
重写两个子类内部的方法
在这里插入图片描述

使用多态接口,传入父类的指针,调用传入子类的 重写的方法。
在这里插入图片描述

虚析构 和 纯虚析构

在这里插入图片描述
用小猫和Animal的父类子类举例:

其构造函数中,在堆区new一个字符串,m_Name指向这个字符串。

在这里插入图片描述发现cat的析构函数没有执行,也就是说m_Name没有被释放

修改父类中的析构函数为虚析构:
在这里插入图片描述
在这里插入图片描述
总结:
在这里插入图片描述

组装电脑的例子

在这里插入图片描述

  1. 创建三个大类:CPU,GPU,Memory
//三个零件 抽象类:

//CPU基类/父类
class CPU {

public:
	virtual void caculate() = 0;

};

class GPU {

public:
	virtual void show() = 0;

};


class Memory {

public:
	virtual void storage() = 0;

};
  1. 创建电脑类,通过指针获取构造函数传入的零件,调用零件内的功能。
// 电脑类:
class Computer {

public:		//记得加权限
	//构造时传入三个指针,并保存在本类中
	Computer(CPU* cpu, GPU* gpu, Memory* mem) {
		this->m_cpu = cpu;
		this->m_gpu = gpu;
		this->m_mem = mem;
	}

	void dowork() {
		//分别调用传入的三个类,对应的方法
		m_cpu->caculate();
		m_gpu->show();
		m_mem->storage();
	}

	//用来释放下面的三个零件指针
	~Computer() {
		if (m_cpu != NULL) {
			delete m_cpu;
			m_cpu = NULL;
		}
		if (m_gpu != NULL) {
			delete m_gpu;
			m_gpu = NULL;
		}
		if (m_mem != NULL) {
			delete m_mem;
			m_mem = NULL;
		}

	}

// 三个零件指针
private:
	CPU* m_cpu;
	GPU* m_gpu;
	Memory* m_mem;
};
  1. 创建这两个品牌的零件,重写内部功能
//两个具体厂商:
class IntelCPU :public CPU {
public:
	//重写抽象类中的虚函数
	void caculate() {
		cout << "IntelCPU" << endl;
	}
};

class IntelGPU :public GPU {
public:
	void show() {
		cout << "IntelGPU" << endl;
	}
};

class IntelMem :public Memory {
public:
	void storage() {
		cout << "IntelMem" << endl;
	}
};

class LenCPU :public CPU {
public:
	void caculate() {
		cout << "LenCPU" << endl;
	}
};

class LenGPU :public GPU {
public:
	void show() {
		cout << "LenGPU" << endl;
	}
};

class LenMem :public Memory {
public:
	void storage() {
		cout << "LenMem" << endl;
	}
};
  1. 创建对象,用指针定位,再把指针传入构造函数,并调用对象功能。
void test01() {
	IntelCPU* icpu = new IntelCPU;
	IntelGPU* igpu = new IntelGPU;
	IntelMem* imem = new IntelMem;
	//也可以:
	//CPU* icpu = new IntelCPU;
	//GPU* igpu = new IntelGPU;
	//Memory* imem = new IntelMem;

	Computer* computer1 = new Computer(icpu, igpu, imem);
	computer1->dowork();

	delete computer1;	//释放new出来的对象

}
;