C++中的静态和动态多态

之前学过继承,子类继承父类的属性,多态就是基于继承而来的,我们在如果只用继承,那么子类继承父类的各种属性在编译环节,就已经被确认了,导致代码不灵活。如果继承下来的某个子类不支持某种问题的解决,那么父类就需要重新编写代码,这样这个子类ok了,其他子类却有可能出现问题。

多态的好处:灵活,提高代码的可复用性。

1、多态的分类

1、静态多态:函数重载和运算符重载属于静态多态,复用函数名(编译期多态);

2、动态多态:派生类和虚函数实现运行时多态(运行期多态)。

函数重载就不必多说了,就是函数名的复用;运算符重载也类似于函数重载,相当于把符号的功能扩大了,同一个符号或者函数,能够实现多种功能,它们都是在编译的时候绑定了,以后都不能改变了,所以叫编译器多太。

2、动态多态的实现

我们以汉堡为例,汉堡为父类,鸡腿堡和牛肉保都继承了汉堡类。

C++中的静态和动态多态_第1张图片

代码:

#include
using namespace std;

class baseHamburger//父类------汉堡类
{
public:

	void Material()
	{
		cout << "汉堡的配方为:面包、酱汁、蔬菜、肉饼"<

C++中的静态和动态多态_第2张图片

从代码可知,我们父类和2个子类内存在3个同名的函数Material(),我们创建p1和p2,他们都是默认调用类内的Material()函数,而不是调用父类的Material()函数,在程序编译的时候就确认了Material()函数的地址。如果我们想要调用父类的Material()函数,那么只需要加作用域就行。这也是我们最常见的情况。

如果我们这样写

#include
using namespace std;

class baseHamburger//父类------汉堡类
{
public:

	void Material()
	{
		cout << "汉堡配方为:面包、酱汁、蔬菜、肉饼" << endl;
	}
};

class chickenHamburger:public baseHamburger//子类1------鸡腿堡类
{
public:

	void Material()
	{
		cout << "汉堡配方为:面包、酱汁、蔬菜、鸡肉饼" << endl;
	}
};

class beefHamburger :public baseHamburger//子类2------牛肉堡类
{
public:

	void Material()
	{
		cout << "汉堡配方为:面包、酱汁、蔬菜、牛肉饼" <

 

 我们创建一个吃的eat()函数,函数参数为父类对象,函数体为父类对象指向和子类同名的函数,

此时,编译器默认调用了父类的Material()函数,为什么呢?

1、我们明明创建的是子类对象,那应该调用的是子类的Material()呀!

2、传入eat()函数的参数是父类对象,那应该就是调用父类的Material()呀!

是不是感觉有歧义?

那怎么解决呢?

只需要在父类的Material()函数前加上virtual关键字就可以解决问题。

class baseHamburger//父类------汉堡类
{
public:

	virtual void Material()//虚函数
	{
		cout << "汉堡配方为:面包、酱汁、蔬菜、肉饼" << endl;
	}
};

加上virtual关键字后函数就变成了虚函数,程序运行的时候才确定Material()函数的地址。

有的同学可以说,我直接创建几个不同的函数名不就行了?

这样确实可以,但是你别忘了这个问题是在同名函数,我们要复用函数名前提下提出来的。

而且就算你创建很多个不同的函数名,那代码量不就上来了?且每一个eat()函数的参数都要额外写一个子类对象,函数体实现也就变得复杂了。

我们的目的是传入什么对象,那么就调用什么对象的函数,这也是动态多态的好处。

3、 动态多态的满足条件

1、有继承关系;
2、子类重写父类中的虚函数。

动态多态使用:
父类指针或引用指向子类对象,就像我们的eat()函数一样。

 4、多态内部原理

当我们继承了父类中的函数的时候,那仅仅是继承了这个函数,其内部是通过虚函数表指针(vfptr)的和虚函数表(vftable)来控制的,vfptr又指向vftablevftable内存放了所有父类的函数地址,vfptr就指向这些地址,所以子类的内部就固定存在父类的一份vfptrvftable拷贝,这是最一般的情况。

但是当我们将父类的函数改为虚函数的时候,且在子类重写父类的虚函数,那就不一样了,当我们用父类指针指向子类对象的时候,vftable中同名函数的作用域就从父类变成的子类,相当于把父同名类函数的地址改为子类同名函数的地址。

你可能感兴趣的:(C++学习,c++,开发语言,后端)