C++多态

欢迎来到本期节目- - -
C++多态
Dog Sheep mouse   talk   汪汪 咩咩 吱吱

虚函数

虚函数

定义:

|---------------------------------------|
| ++在类成员函数前加上virtual,则该函数被称为虚函数;++ |
| ++虚函数的目的是为了实现多态;++ |
| ++虚函数可以给出目标函数的定义,但该目标的具体指向在编译期无法确定;++ |

定义格式:

cpp 复制代码
class Examples
{
public:
	virtual void func()
	{
		cout << "I am virtual function" << endl;
	}
}

注意:

|------------------------------|
| ++虚函数的virtual只能修饰类的非静态成员函数++ |

纯虚函数与抽象类

纯虚函数定义:

|---------------------------------|
| ++在虚函数的后方写上 =0,则这个函数被称为纯虚函数;++ |
| ++纯虚函数不需要定义实现(可以实现函数体,但是不实用);++ |

定义格式:

cpp 复制代码
class Examples
{
public:
	virtual void func()=0;	//通常只写声明
}

抽象类定义:

|-----------------------------------|
| ++含有纯虚函数的类被称为抽象类;++ |
| ++抽象类不能被直接实例化;++ |
| ++如果继承抽象类的子类没有重写虚函数,那么该子类也是抽象类;++ |

重写/覆盖

虚函数重写定义:

|---------------------------------------------------------|
| ++子类中的实现通过提供与父类中的方法具有相同函数名,相同参数类型,相同返回类型的方法来覆盖父类中的实现;++ |
| ++本质是在重写函数体;++ |

重写构成条件

  • 父类必须是虚函数;
  • 子类中的该虚函数必须是与父类中虚函数具有相同的函数名,相同的参数类型,相同的返回类型;
    但是有一种特殊情况:协变
    • 返回类型可以是一对基类和派生类的指针或引用(不一定是当前类,可以是别类);

定义格式:

cpp 复制代码
class animal
{
public:
	virtual void Fond()=0;	
};

class monkey:public animal
{
public:
	virtual void Fond()	//virtual可以不加也构成重写,因为被继承下来了--但是为了养成良好的编程风格,建议加上
	{
		cout << "I Like Monkey" << endl;
	}
}

多态

多态定义:

|------------------------|
| ++是指为不同数据类型实体提供统一接口;++ |
| ++或者说使用统一接口表现出不同形态;++ |

多态构成条件

  • 必须是基类指针或者引用调用;
  • 调用的函数是经过重写的虚函数;
cpp 复制代码
class EveryMan
{
public:
	virtual void read_books()	
	{
		cout << "I can read 2 pages" << endl;
	}
};

class LearnGod:public EveryMan
{
public:
	virtual void read_books()//构成重写
	{
		cout << "I've read 2 books now" << endl;
	}
};

void func1(EveryMan* ptr)
{
	ptr->read_books();	//基类指针+构成重写的虚函数---多态
}
void func2(EveryMan& ref)
{
	ref.read_books();//基类引用+构成重写的虚函数---多态
}	


void test()
{
	EveryMan ordinary;
	LearnGod talent;

	func1(&ordinary);	//传谁调用谁的接口
	func1(&talent);
//--------------------------------------	
	func2(ordinary);
	func2(talent);
}

或者另外一种方式

cpp 复制代码
class EveryMan
{
public:
	virtual EveryMan* read_books()
	{
		cout << "I can read 2 pages" << endl;
		return this;
	}
};

class LearnGod:public EveryMan
{
public:
	virtual LearnGod* read_books()	//构成协变
	{
		cout << "I've read 2 books now" << endl;
		return this;
	}
};

void func1(EveryMan* ptr)
{
	ptr->read_books();	//基类指针+构成协变的虚函数---多态
}
void func2(EveryMan& ref)
{
	ref.read_books();//基类引用+构成协变的虚函数---多态
}	


void test()
{
	EveryMan ordinary;
	LearnGod talent;

	func1(&ordinary);	//传谁调用谁的接口
	func1(&talent);
//--------------------------------------	
	func2(ordinary);
	func2(talent);
}

注意:

|------------------------------------------------------------------------------------|
| ++析构函数也可以支持多态,在经过编译器处理之后,析构函数都会被处理为~destructor(),所以如果基类函数是虚函数,那就构成重写,也就可以有多态行为;++ |

多态底层原理:

那么多态究竟是如何实现指向哪个实体调用哪个实体接口的呢?

底层上,一个基类的所有虚函数地址会放在一个虚函数表中,这个虚函数表就是一个存放该类虚函数地址的一个静态指针数组;
当子类继承该父类时,会把虚函数表继承下来(效果类似深拷贝,因为虚函数表是属于一个类的);
在子类中如果重写了虚函数,就会在子类的虚函数表把基类对应的虚函数地址覆盖,所以就可以指向谁调用谁的接口;

上图:

动态绑定与静态绑定

静态绑定(早绑定)

|----------------------------------|
| ++对不满足多态条件的函数调用时在编译时确定调用函数的地址;++ |

常见case:

  • 函数重载;
  • 函数模板;

动态绑定(迟绑定)

|-------------------------------------------|
| ++满足多态条件的函数调用会在运行时,到指向对象的虚函数表确定调用函数的地址;++ |

常见case:

  • 基类指针或引用的多态行为;

希望本片文章对您有帮助,请点赞支持一下吧😘💕

相关推荐
点云SLAM12 分钟前
C++中的算术转换、其他隐式类型转换和显示转换详解
c++·static_cast·dynamic_cast·c++中的类型转换·算术类型转换·其他隐式类型转换·显示类型转换
海洋与大气科学31 分钟前
【matlab】地图上的小图
开发语言·数据库·matlab
Zfox_39 分钟前
Git 进阶之路:高效协作之分支管理
大数据·linux·运维·c++·git·elasticsearch
wenchm1 小时前
细说STM32单片机FreeRTOS任务管理API函数vTaskList()的使用方法
c语言·c++·stm32·单片机·嵌入式硬件
wuqingshun3141591 小时前
蓝桥杯 10.拉马车
数据结构·c++·算法·职场和发展·蓝桥杯·深度优先
Java知识库1 小时前
Java BIO、NIO、AIO、Netty面试题(已整理全套PDF版本)
java·开发语言·jvm·面试·程序员
techdashen1 小时前
性能比拼: Rust vs Zig vs Go
开发语言·golang·rust
爱编程的鱼1 小时前
C# 封装教程
开发语言·c#
0wioiw01 小时前
Kotlin基础(①)
android·开发语言·kotlin
西瓜本瓜@1 小时前
在 Android 中实现通话录音
android·java·开发语言·学习·github·android-studio