C++多态学习笔记

2019/3/7 C++多态学习笔记

多态是面向斜体样式对象语言中数据封装和继承之外的第三种基本特征。多态改善了代码的可读性和组织性,同时也使创建的程序具有可扩展性,即项目不仅在最初创建时可以扩展,在项目需要有新的功能时也能扩展。
多态分为编译时多态(静态多态)和运行时多态(动态多态)。其中重载就是编译时多态,而子类和虚函数实现的为运行时多态。
静态多态和动态多态的区别就是静态在编译时就可以确定函数的调用地址,并产生代码。而动态多态只有在运行时才能决定。

#include <iostream>
using namespace std;
class animal
{
public:
	void eat() {
		cout << "动物吃食物!" << endl;
	}
};
//*******************************************************
class cat:public animal
{
public:
	void eat() {
		cout << "猫吃猫粮!" << endl;
	}
};
//*******************************************************
int main() {
	animal *a = new cat();
	a->eat();
	system("pause");
	return 0;
}

我们都知道上面那个代码的运行结果肯定是:“动物吃食物!”
在这里插入图片描述
因为那个对象a是animal类型的,程序编译时eat函数的地址就更animal绑定在一起。所以该程序想输出“猫吃猫粮!”,就得定义cat类型得对象。但是如果我们在代码中加入动物的名字,并创建一个person类,动物为人的宠物。

class cat:public animal
{
public:
	void eat() {
		cout << "猫吃猫粮!" << endl;
	}
	void name() {
		cout << "猫" << endl;
	}
};
//**********************************************
class person
{
public:
	void pets(cat a) {
		cout << "宠物为:" << a.name() << endl;  //这里的cout可能要用上运算符重载
			}
};

我们在person类中创建个函数,参数为cat类型的对象,这么就可以输出人宠物的名字。但是,这里的例子只有cat类,这么自然看不出什么问题,如果在来几个dog类,pig类,hamster类甚至更多动物类,难道要在person类中把这些类作为参数的函数都重载一下吗?显然不可能。所以这里就用到多态。
实现多态只需要在基类中将可能多种实现方法的函数的类型前加上virtual关键字将其设置成虚函数。

class animal
{
public:
	virtual void eat() {
		cout << "动物吃食物!" << endl;
	}
	virtual void name() {
		cout << "动物名字" << endl;
	}
};

而person类则改成

class person
{
public:
	void pets(animal a) {
		cout << "宠物为:" << a.name()<< endl;
	}
};

这样就不需要创建那么多的重载函数,每次只传入animal类型的子类对象,就可以输出相应的动物名字,极大的减少了代码量和扩充了程序的可扩展性。
我们此时还是调用最先的main函数`

int main() {
	animal *a = new cat();
	a->eat();
	system("pause");
	return 0;
}

而此时的输出的是“猫吃猫粮”。
在这里插入图片描述
为什么相同的代码,只在函数前加上virtual后输出就不一样了呢?因为类里出现virtual后,类里就有个指向虚函数表的vfptr指针(虚函数指针)。
在这里插入图片描述
在这里插入图片描述
如图,当我们创建一个空类,没有任何变量,调用sizeof()可知道此时类大小为1;当在类里面的函数加上virtual后,再调用sizeof(),此时大小为4.就是因为此时类里出现一个vfptr。
当你创建animal类后,他的结构如下图,eat()函数为虚函数,所以这个函数在虚函数表。
在这里插入图片描述
当我们在创建一个cat类,并继承namial类后,它会把animal类的vfptr和虚函数表全部继承过去。但是此时cat类的vfptr指向namial类的虚函数表,当创建一个对象时,程序自动将cat类的vfptr指向自己的虚函数表
在这里插入图片描述
在这里插入图片描述
如果cat类在继承animal类后,重写(即函数返回值,参数个数,参数类型,参数顺序都相同)了eat函数,此时cat类的虚函数表里的&animal:: eat就被&cat::eat覆盖。如图
在这里插入图片描述
所以不管你创建的对象时什么类型的,他调用的都是对象的函数。

animal *a=new cat;
如果是只是继承,那“=”左边是什么,a调用的就是谁的函数。
如果是多态,那“=”右边是什么,a调用的就是谁的函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值