IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++Day71.0 -> 正文阅读

[C++知识库]C++Day71.0

多态的实质:父类的引用或指针指向子类对象

怎么理解?
假设我们现在有如下的类,其中Animal为基类,Cat和Dog都是其派生类。

class Animal{
public:
	virtual void speak(){
		cout << "动物在说话" << endl;
	}
};
 
class Cat :public Animal{
public:
	void speak(){
		cout << "小猫在说话" << endl;
	}
};
 
class Dog :public Animal{
public:
	void speak(){
		cout << "小狗在说话" << endl;
	}
 
};

1.父类指针指向子类对象
调用时,可以定义父类的指针,然后指向子类的对象,指向哪个对象,便执行其对象的虚函数实现

int main() {
	方法1:
	
	Dog B;
	Animal *A=&B;
	A->speak();
	
	如果你不想给Dog类取名:
	Animal *A=new Dog;
	A->speak();
	
	方法2:
	
	A=new Cat;//如果小猫有名字A=new Cat("名字");
	A->speak();
	
	return 0;
}

2.父类引用指向子类对象
这种实现,我们需要额外定义一个“实现函数”,其参数是基类的引用(否则不能实现多态)。这样在调用时就实现了父类引用指向子类对象。

void DoSpeak(Animal & X){ //
	X.speak();
}
 
int main() {
	
	Cat A;
	DoSpeak(A);
 
	Dog B;
	DoSpeak(B);
	
	Animal C;
	DoSpeak(C);
	
	return 0;
}

.
.
.

一.静态联编与动态联编
多态分为:

  • 静态联编:如函数重载

    • 地址早绑定,编译阶段就确定好了地址(在写完这条语句就被绑定了)
  • 动态联编:如虚函数,继承关系
    -地址晚绑定,运行的时候才绑定好地址

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

class Animal
{
public:
	virtual void speak()//加了virtual关键字,变成了虚函数
	{
		cout << "动物在说话" << endl;
	}

private:

};

class Cat:public Animal
{
public:
	void speak()//子类的virtual可写可不写
	{
		cout << "小猫在说话" << endl;
	}

private:

};

//当调用DoSpeak时,speak函数的地址早就绑定好了(静态联编),也就是绑定在class Animal中
//如果我们想要调用猫的DoSpeak函数,就不能提前绑定好speak函数的地址,而是在运行的时候再去确定(改成动态联编)

//动态联编的写法:把DoSpeak中的函数改成虚函数(+virtual关键字)
void DoSpeak(Animal& animal)	多态的实质:父类的引用或指针指向子类对象
{
	animal.speak();
}

//如果发生了继承的关系,编译器允许进行类型转换
void test01()
{
	Cat cat;
	DoSpeak(cat);//此行不会报错!因为Cat和Animal发生了继承的关系
}

int main()
{
	test01();

	system("pause");
	return 0;
}

.
.
.
二.多态原理解析

  • 当父类中有了虚函数(virtual)后,内部结构发生了改变

  • 内部多了一个virptf指针

    • virtual function pointer 虚函数表指针
    • 指向vftable虚函数表
  • 父类中的结构有:virptf虚函数表指针 vtfable虚函数表

  • 子类中进行继承,会继承父类的virptf虚函数表指针 vtfable虚函数表

  • 在子类的构造函数中,会自动将自己继承下来的virptf虚函数表指针指向自己的vtfable虚函数表

  • 如果子函数中发生了重写,会替换掉vtfable虚函数表中原有的speak,变成Cat::speak

    • 重写:子类写speak父类的虚函数,重写必须返回值,参数个数,类型,顺序都相同

.
.
.
三.抽象基类和纯虚函数
如果父类中有一些函数,它不需要任何的实现,只想让子类通过多态做新的实现(如计算机案例),此时可以用抽象类,也就是在类中加入至少一个纯虚函数,使得基类被称为抽象类

  1. 纯虚函数使用关键字virtual,并在其后面加上=0,如果试图去实例化一个抽象类,编译器会制止(报错)
  2. 当Calculator是一个抽象基类时Calculator cal ;Calculator * cal = new Add_Calculator都会报错!(也就是Calculator里面含有纯虚函数)
  3. 当继承一个抽象类时,必须实现所有的纯虚函数(也就是通过多态进行改写),否则由抽象类派生的类也是一个抽象类
    .
    .
    .

四.虚析构和纯虚析构

虚析构:

  1. 调用形式:virtual~类名(){}
  2. 解决问题:通过父类指针指向子类对象释放时释放不干净的问题(普通的析构是不会调用子类的析构的,也就是子类的析构函数无法被调用,所以可能会释放不干净)

纯虚析构函数:

  1. 调用形式:virtual~类名()=0 类内声明,类外实现类名::~类名(){}
  2. 如果出现了纯虚构函数,这个类也算是抽象类,不能进行实例化

以给小动物取名为例

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;

class Animal
{
public:
	virtual void speak()
	{
		cout << "动物在说话" << endl;
	}

	~Animal()
	{
		cout << "Animal的析构函数调用" << endl;
	}
private:

};

class Cat :public Animal
{
public:
	//给小猫起个名字(拷贝构造函数)
	Cat(const char* name)
	{
		//由于是在堆上开辟的空间,所以要考虑深浅拷贝的问题
		this->m_name = new char[strlen(name) + 1];
		strcpy(this->m_name, name);
	}
	void speak()
	{
		cout << this->m_name << "在说话" << endl;
	}

	virtual ~Cat()
	{
		cout << "Cat的析构函数调用" << endl;
	}

private:
	char* m_name;
};





void test01()
{
	//多态的实质:父类的引用或指针指向子类对象
	Animal* animal = new Cat("TOM");
	animal->speak();

	delete animal;
}

int main()
{
	test01();

	
	system("pause");
	return 0;
}

如果不调用虚析构函数,那么Cat类的析构不会被调用
在这里插入图片描述
调用了虚析构函数,才会把子类的数据给清理掉!
在这里插入图片描述
纯析构函数的写法

class Animal
{
public:
	virtual void speak()
	{
		cout << "动物在说话" << endl;
	}

	virtual~Animal() = 0;
	
private:

};
Animal::~Animal()
{
	//纯虚析构函数实现
	cout << "纯虚析构函数调用" << endl;
}

文章转自布尔博客
欢迎关注技术公众号,获取更多硬件学习干货!

在这里插入图片描述

我们能为你提供什么?
技术辅导:C++、Java、嵌入式软件/硬件
项目辅导:软件/硬件项目、大厂实训项目
就业辅导:就业全流程辅导、技术创业支持
对接企业HR:培养输送优质性人才

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-07 13:40:26  更:2021-10-07 13:42:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/29 18:29:40-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计