多态实现及虚函数

多态是C++面向对象三大特性之一
多态分为两类:
1.静态多态:函数重载和运算符重载属于静态多态
2.动态多态:派生类与虚函数实现运行时多态
区别:
静态多态的函数地址早绑定-编译阶段确定函数地址
动态多态的函数地址晚绑定-运行阶段确定函数地址

class Animal{
public:
	void speak(){
		cout<<"动物在说话"<<endl;
		}
}
class Cat:public Animal{
public:
	void speak(){
		cout<<"小猫在说话"<<endl;
		}
}
//属于函数重载,地址早绑定,所以不管传入的是什么类,输出的都是Animal类
void Speak(Animal & animal){//Animal &animal=cat
	animal.speak();
}
int  main(){
	Cat cat;
	Speak(cat)
	system("pause");
	return 0;
}

上述代码输出的结果是:动物在说话

若想实现输出:小猫在说话。需要采用动态多态

class Animal{
public:
	//加上virtual关键字,成为虚函数,这样在执行函数的时候,就可以实现地址晚绑定
	virtual void speak(){
		cout<<"动物在说话"<<endl;
		}
}
//根据传入的不用类,就会执行该类中的同名函数
class Cat:public Animal{
public:
	void speak(){
		cout<<"小猫在说话"<<endl;
		}
}

动态多态满足条件:
1.有继承关系
2.子类要重写父类中的虚函数,完全一样,virtual可加可不不加

动态多态的使用:
父类的指针或引用 指向子类对象

下面讲解一下多态的原理:

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

首先看上面的代码,上面这个类一共占用4个字节,实际上,在Animal中有一个指针,名称为vfptr(虚函数指针),v-virtual f-function ptr-pointer,该指针指向vftable(虚函数表),在该表中储存 的是虚函数的地址,即&Animal::speak.

我们在定义它的一个子类:

class Cat:public Animal{
public:
	//重写父类中的虚函数,virtual可加可不加
	void speak(){
		cout<<"小猫在说话"<<endl;
		}
	//若是在 Cat类中什么 都不写,那么Cat类中虚函数表记录的是  &Animal::speak
}

此时,在 Cat类中,在vftable(虚函数表)中储存 的地址既是&Cat::speak,而不再是&Animal::speak。也就能输出我们想要的结果。

在多态中,通常父类中的虚函数的实现都是毫无意义的,主要都是 调用子类中重写的内容。
因此可以将父类中的虚函数改为纯虚函数。
语法:virtual 返回值类型 函数名(参数列表)= 0;
当类中有了纯虚函数,这个类也称为抽象类。
抽象类特点:
无法实例化对象
子类必须重写抽象类中的纯虚函数,否则也属于抽象类

**

虚析构和纯虚析构

**
多态使用时,如果子类有属性开辟到堆区,那么父类指针在释放时无法调用子类中的析构函数
解决方式:将父类中的析构函数改为虚析构或纯虚析构,这样父类指针在释放时就可以 调用子类的析构函数,继而能释放的开辟在子类中的空间。
虚析构和纯虚析构共性:
可以解决父类指针释放子类对象
都需要有具体的函数实现
区别:
如果是纯虚析构,该类属于抽象类,无法实例化对象
如果写成纯虚函数,必须要在类外实现一下,即使是空实现。

class Base{
public:
	virtual ~Base()=0;
	}
Base::~Base(){
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值