C++ 类和对象-多态

本文介绍了C++中的多态性,包括静态多态(函数重载和运算符重载)和动态多态(通过虚函数实现)。静态多态在编译阶段绑定函数地址,而动态多态在运行时确定。通过实例展示了如何利用虚函数实现动态多态,以及vfptr和vftable在多态中的作用。同时,通过VS开发人员命令行工具观察类布局变化,进一步解释了动态多态的工作机制。
摘要由CSDN通过智能技术生成

多态的基本概念

多态是C++面向对象三大特性之一

多态分为两类

  • 静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名
  • 动态多态: 派生类和虚函数实现运行时多态

静态多态和动态多态区别:

  • 静态多态的函数地址早绑定 - 编译阶段确定函数地址
  • 动态多态的函数地址晚绑定 - 运行阶段确定函数地址
#include<iostream>
using namespace std;

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

class Dog : public Animal
{
public:
	void speak()
	{
		cout << "狗在说话" << endl;
	}
};

class Cat : public Animal
{
public:
	void speak()
	{
		cout << "小猫在说话" << endl;
	}
};

void doSpeak(Animal& animal)
{
	animal.speak();
}

void test01()
{
	Cat cat;
	doSpeak(cat);
	Dog dog;
	doSpeak(dog);

}
int main()
{
	test01();
	system("pause");
	return 0;
}

上述代码输出结果
在这里插入图片描述
我们发现并没有按照我们设想的那样打印“猫在说话;狗在说话”
这是因为:
//地址早绑定 在绑定阶段就确定函数地址
//如果想执行让猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段进行绑定,地址晚绑定
想要让函数地址晚绑定,那么需要将speak这个函数变为虚函数,改动如下;

class Animal
{
public:
	//Speak函数就是虚函数
	//函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。
	virtual void speak()
	{
		cout << "动物在说话" << endl;
	}
};

改动后的完整代码如下:

#include<iostream>
using namespace std;

class Animal
{
public:
	//Speak函数就是虚函数
	//函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。
	virtual void speak()
	{
		cout << "动物在说话" << endl;
	}
};

class Dog : public Animal
{
public:
	//重写,函数返回值类型 函数名 参数列表 完全相同
	void speak()
	{
		cout << "狗在说话" << endl;
	}
};

class Cat : public Animal
{
public:
	void speak()
	{
		cout << "小猫在说话" << endl;
	}
};

void doSpeak(Animal& animal)
{
	animal.speak();
}

void test01()
{
	Cat cat;
	doSpeak(cat);
	Dog dog;
	doSpeak(dog);

}

int main()
{
	test01();
	system("pause");
	return 0;
}

上述输出结果
在这里插入图片描述
正常输出小猫在说话,小狗在说话

我们使用VS 开发人员命令行工具看一下执行上述代码对象发生的变化
先看下没有加virtual时是什么
首先打开Developer Command Prompt for VS 2019(我使用的是vs2019)
在这里插入图片描述
然后切换到项目文件盘符
在这里插入图片描述
我这里放在了E盘中
然后切换到项目文件(自己创建的项目文件)
在这里插入图片描述
然后使用命令行 ’cl /d1 reportSingleClassLayoutAnimal 01多态基本概念.cpp’
(reportSingleClassLayoutCat意思是打印报告单个类动物;01多态基本概念.cpp是我的源文件)
在这里插入图片描述
这里可以看到Animal这个类的大小是1,是个空类
现在我们加上virtual,再看下Animal的大小
在这里插入图片描述
发现现在的大小变成了4,这个大小是一个指针的大小,这个指针就是vfptr,可以在图中看出,这个指针指向了vftable,vftable里面存储的就是Animal::speak这个函数。

接下来我们看Cat这个类发生了什么变化
先在Cat类中不进行函数重写
即讲下列代码中speak函数注释

class Cat : public Animal
{
public:
//	void speak()
//	{
//		cout << "小猫在说话" << endl;
//	}
};

然后使用命令行 ’cl /d1 reportSingleClassLayoutCat 01多态基本概念.cpp’
在这里插入图片描述
这里同样的有个指针vfptr,可以在图中看出,这个指针指向了vftable,vftable里面存储的是Animal::speak这个函数,所以执行结果是“动物在说话”
然后对Cat 类里函数进行重写
查看输出结果
在这里插入图片描述
发现vftable里面存储的是Cat::speak这个函数,所以执行结果是“小猫在说话”

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值