c++多态的理解

多态性是一个接口多种实现,是面向对象的核心
正常情况下,函数的地址在编译过程中就已经确定,在运行中无法更改,但是通过晚绑定机制可以在运行阶段在确定函数的地址,从而实现多态的效果。

非多态继承情况下,早绑定示例

#include <iostream>
using namespace std;
class Animal
{
public:
	/*virtual*/ void CreateAnimal();
	/*virtual void Sound();*/
};

void Animal::CreateAnimal()
{
	std::cout << "--- Animal---" << std::endl;
}

Dog继承与Animal,并且对CreateAnimal函数进行重写

#include "Animal.h"
class DogAnimal :
    public Animal
{
public:
   /* virtual*/ void CreateAnimal();
  /*  virtual void Sound();*/
};

void DogAnimal::CreateAnimal()
{
	std::cout << "--- Dog---" << std::endl;
}

调用类对象打印函数

void fun(Animal* animal)
{
	animal->CreateAnimal();
}

int main()
{
	Animal* animal = new Animal;
	Animal* doganimal = new DogAnimal;

	fun(animal);
	fun(doganimal);
	
	delete animal;
	animal = nullptr;
	delete doganimal;
	doganimal = nullptr;
}

我们发现在调用过程中,结果调用的都是基类的 CreateAnimal 。。。
这就是早绑定,函数参数本身为Animal,在编译过程中对其函数地址进行绑定,此时就算Dog类型成功转换,但是调用的仍旧是基类。

在这里插入图片描述

多态的实现

将CreateAnimal定义为虚函数,现在对虚函数进行重写操作。

#include <iostream>
using namespace std;

class Animal
{
public:
	virtual ~Animal();
	virtual void CreateAnimal();
	virtual void Sound();
};


#include "Animal.h"
class DogAnimal :
    public Animal
{
public:
    virtual void CreateAnimal();
    virtual void Sound();
};

调用CreateAnimal函数,以及打印虚函数表中函数的地址。

int main()
{
	Animal* animal = new Animal;
	Animal* doganimal = new DogAnimal;
	
	fun(animal);
	fun(doganimal);

	LL* pint = (LL *)animal;
	LL* vptr = (LL*)(*pint);
	std::cout << "虚函数表地址:" << *vptr << std::endl;
	std::cout <<"Animal::CreateAnima:" << vptr[0] << std::endl;
	std::cout <<"Animal::Soun:" << vptr[1] << std::endl;

	LL* pint2 = (LL*)doganimal;
	LL* vptr2 = (LL*)(*pint2);
	std::cout << "虚函数表地址:" << *vptr2 << std::endl;
	std::cout << "DogAnimal::CreateAnimal:" << vptr2[0] << std::endl;
	std::cout << "DogAnimal::Sound:" << vptr2[1] << std::endl;

	delete animal;
	animal = nullptr;
	delete doganimal;
	doganimal = nullptr;
}

在这里插入图片描述
通过打印结果发现,重写的虚函数 CreaterAnImal 拥有了属于自己的地址,未重写的函数 Sound ,依旧是使用父类虚函数的地址,但是调用时,DogAnimal调用的是自己的CreateAnimal函数,也就是说在这次示例中,CreateAnimal函数的地址并没有在编译阶段就确定下来(否则的话就会调用父类的CreateAnimal函数),而是在运行时去确定对象的类型,根据对象中虚指针指向的虚表中的函数的地址来确定调用哪个函数

正常情况下,在编译过程中就已经确定了对象调用的函数的地址,要解决这个问题就要使用迟绑定(late binding)技术。当编译器使用迟绑定时,就会在运行时再去确定对象的类型以及正确的调用函数。而要让编译器采用迟绑定,就要在基类中声明函数时使用virtual关键字,这样的函数我们称为虚函数。一旦某个函数在基类中声明为virtual,那么在所有的派生类中该函数都是virtual,而不需要再显式地声明为virtual。

类的多态性,是指用虚函数和延迟绑定来实现的。函数的多态性是函数的重载。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值