C++多态:(1)虚函数,案例1

本文介绍了C++中的多态性,包括静态多态和动态多态的概念。重点讲解了动态多态,强调了其在继承关系、虚函数重写和虚函数指针的作用。通过一个计算机类的案例展示了动态多态的实现和优点,如代码结构清晰、可读性强和易于扩展维护。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

多态的基本概念

多态是C++面向对象三大特性之一;
多态分为两大类:
1.静态多态:函数重载 和 运算符重载属于静态多态,复用函数名;
2.动态多态:派生类和弧函数实现运行时多态;

(我们讲的多态多为动态多态)

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

  • 静态多态的函数地址早绑定 ——编译阶段确定函数地址;
    动态多态的函数地址晚绑定 ——运行阶段确定函数地址;
class Animal {
public:
	speak()就是虚函数
	函数前面加上关键字virtual,变成虚函数,那么编译器在编译的时候就不能确定函数调用了;
	 virtual void speak() {
		cout << "动物在说话" << endl;
	}
};
class Cat :public Animal {
public:
	重写  函数返回值类型  函数名  参数列表 完全相同
	void speak() {
		cout << "猫在说话" << endl;
	}
};
class Dog :public Animal {
public:
	//重写  函数返回值类型  函数名  参数列表 完全相同
	void speak() {
		cout << "狗在说话" << endl;
	}
};
执行说话的函数
地址早绑定  在编译阶段确定函数地址
如果想执行让猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段进行绑定,地址晚绑定;
void doSpeak(Animal &animal) {
 Animal &animal = cat  父类的指针或者引用-执行子类对象
	animal.speak();
}

int main() {
	Cat cat;
	doSpeak(cat);

	Dog dog;
	doSpeak(dog);
	system("pause");
	return 0;
}

总结:
动态多态满足条件
1.有继承关系
2.子类重写父类的虚函数
3.父类虚函数利用关键字:virtual声明,然后在子类中重写;

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

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

执行说话的函数
地址早绑定  在编译阶段确定函数地址
如果想执行让猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段进行绑定,地址晚绑定;
void doSpeak(Animal &animal) {
 Animal &animal = cat  父类的指针或者引用-执行子类对象
	animal.speak();
}

Cat cat;
doSpeak(cat);

多态的原理剖析:

测试:
1.原空Animal类,sizeof大小为1;
2.当把speak()函数设置为virtual,设置为虚函数时,sizeof对象大小为4;
在这里插入图片描述

即对象变为vftr模型:
vfptr:(1).v:virtual:虚拟 (2).f:function;函数 (3).ptr:pointer;指针
所以,vfptr:虚函数(表)指针;——即指向虚函数表的指针;
vftable:虚函数表(表内记录虚函数地址)
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
测试:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

案例1:计算机类

在这里插入图片描述

  • 多态的优点:
  • 1.代码组织结构清晰
  • 2.可读性强;
  • 3.利于前期和后期的扩展以及维护;
    普通写法写计算器:
class Calculator {
public:
	int getResult(string oper) {
		if (oper == "+") {
			return m_Num1 + m_Num2;
		}else if (oper == "-") {
			return m_Num1 - m_Num2;
		}
		else if (oper == "*") {
			return m_Num1 * m_Num2;
		}
	}
	//如果想扩展新的功能,需求修改源码
	//在真实的开发中提倡:开闭yuanze
	//开闭原则:对扩展进行开发,对修改进行关闭
	int m_Num1;
	int m_Num2;
};

缺点:
如果想扩展新的功能,需求修改源码

  • 在真实的开发中提倡:开闭原则
    开闭原则:对扩展进行开放,对修改进行关闭
  • 利用多态实现计算机
//实现计算器抽象类--不写功能
class AbstractCalculator {
public:
	//父类中需要有虚函数,再在子类中进行重写
	virtual int getResult() {
		return 0;
	}
	int m_Num1;
	int m_Num2;
};
//加法计算器类
class AddCaluculator :public AbstractCalculator {
public:
	int getResult() {
		return m_Num1 + m_Num2;
	}
};
//减法计算器类
class SubCaluculator :public AbstractCalculator {
public:
	int getResult() {
		return m_Num1 - m_Num2;
	}
};
//乘法计算器类
class MulCaluculator :public AbstractCalculator {
public:
	int getResult() {
		return m_Num1 * m_Num2;
	}
};
int main() {
	//多态使用条件
	//父类指针或者引用指向子类对象
	//加法:
	AbstractCalculator * abc = new AddCaluculator;
	abc->m_Num1 = 10;
	abc->m_Num2 = 20;
	cout << abc->m_Num1 << "+" << abc->m_Num2 << abc->getResult << endl;
	//用完后记得销毁
	delete abc;

	//减法
	abc = new SubCaluculator;
	abc->m_Num1 = 10;
	abc->m_Num2 = 20;
	cout << abc->m_Num1 << "-" << abc->m_Num2 << abc->getResult << endl;
	//用完后记得销毁
	delete abc;

	//乘法:
	AbstractCalculator * abc = new MulCaluculator;
	abc->m_Num1 = 10;
	abc->m_Num2 = 20;
	cout << abc->m_Num1 << "*" << abc->m_Num2 << abc->getResult << endl;
	//用完后记得销毁
	delete abc;

	system("pause");
	return 0;
}
  • 多态好处:
    1.组织结构清晰:–功能分块
    2.可读性强
    3.对于前期和后期扩展以及维护性高;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值