【C++】初识多态!!!

在C++里面多态是一种重要的机制,多态是指“一种形式,多种方式”,在继承体系里面,对象通过基类的指针或引用来调用函数。

多态分为静态多态和动态多态:

静态多态:1、函数的重载

  2、泛型编程

特点:在编译器编译期间就确定好函数的形式(前期绑定)。

动态多态:在程序运行期间才会确定函数的形式(动态绑定)。

要实现动态绑定必须要满足两个条件:1、函数必须是虚函数  2、必须通过基类的指针或者引用来调用。

举个栗子:

#include 
using namespace std;

class Base
{
public:
	virtual void test()
	{
		cout<<"Base::test()"<
运行结果:



在函数实现多态的时候还需要对基类里面的函数进行重写,重写和函数的重载相类似,但是确是有区别的:

【C++】初识多态!!!_第1张图片

协变:在继承体系里面,在基类和派生类里面,基类的徐哈数放回基类的指针或引用,在派生类里面派生类返回派生类的指针或引用。

举个栗子:

class Base
{
public:
	virtual Base & test()
	{
		return *this;
	}
};

class Derived:public Base
{
public:
	virtual Derived & test()
	{
		return *this;
	}
};

多态实现了通过基类的指针或者引用使不同的派生类调用相应的函数,但是在多态里面并不是所有的函数斗志可以实现多态的。

首先,要实现多态必须是虚函数,然后经过在派生类里面对基类里面的函数进行重写。调用的时候必须是通过基类的指针或者引用来实现。

但是在C++里面构造函数,static关键字修饰的函数、友元函数是不可以实现多态的。

1、为什么构造函数不可以定义成虚函数形式?

 解:在构造函数里面是为了初始化对象的,但是调用虚函数的时候首先需要调用对象的地址,在对象的前4个字节里面存储的是虚表的指针,如果将构造函数定义成虚函数的形式那么在寻找对象地址的时候就会发生错误。所以不能将构造函数定义成虚函数的形式。

2、为什么static修饰的函数和友元函数不可以实现多态?

在c++的类在内存里面的存储可以知道,静态函数和友元函数是这个类的公共拥有的函数,所以在这里这两类函数不属于任何一个对象,然而在实现多态的时候需要使用对象来调用虚函数,这里静态函数和友元函数就不可以。

3、为什么析构函数必须定义为虚函数?

当我们在构造某一个对象的时候经常会开辟空间,然后使用析构函数来释放内存,当我们调用派生类函数的时候在基类里面也会开辟一块空间,当我们在使用普通的析构函数来释放内存的时候就会出现,值释放掉了基类里面的内存,但是派生类里面的内存依然存在,这样就会出现内存泄漏的危险。使用虚函数的析构函数的时候,调用的时候就会先释放掉派生类的内存,然后接着就会释放基类的空间,这样就不会出现内存泄漏的问题。



多态的实现机制:

在 C++里面多态的调用是依靠基类的指针或者引用实现的,但是在函数实现的时候却是调用的派生类的函数,这些实现的方法依靠的是虚表完成的。

在每个类的里面,如果含有虚函数,那么在每个对象的前4个字节都会存储虚表的指针,这个指针就是指向虚表的位置,在函数调用的时候函数先会去查表,然后在去调用函数。如图:

【C++】初识多态!!!_第2张图片

这样,在每次调用函数的时候就会调用的特定的函数。

在实现虚表的时候,如果派生类对基类的虚函数进行了重写,那么在派生类里面的虚表就会对基类的虚表进行覆盖

举个栗子:

【C++】初识多态!!!_第3张图片

如图,1、如果在派生类里面如果对基类里面的函数进行了重写,那么在派生类里面的虚表相同的偏移量的地方就会将重写后的函数地址进行替换。

   2、假如在派生类里面含有自己的特有虚函数,那么会将虚函数地址放在基类虚表的后面。     

这样就在使用基类的指针来调用派生类对象的时候就会调用派生类的函数,这样就实现了简单的多态。




你可能感兴趣的:(C\C++)