[C++核心编程](九):类和对象——多态**

目录

多态的分类

多态的原理剖析

多态的优点

纯虚函数和抽象类

虚析构和纯虚析构


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

多态的分类

  • 静态多态

-函数重载 和运算符重载属于静态多态,复用函数名

-函数地址早绑定-编译阶段确定函数地址

  • 动态多态

-派生类和虚函数实现运行时多态

-函数地址晚绑定-运行阶段确定函数地址

动态多态满足条件:

1.继承关系

2.子类要重写(函数返回值类型、函数名、参数列表完全相同)父类的虚函数

动态多态的使用:

父类的指针或者引用 指向 子类的对象

cpp 复制代码
#include <iostream>
#include <string>

using namespace std;

class Animal
{
public:
	//虚函数
	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.speak();
}

void test(void)
{
	Cat cat;
	dospeak(cat);

	Dog dog;
	dospeak(dog);
}

int main(void)
{
	test();
	return 0;
}

多态的原理剖析

父类内部结构 : vfptr-虚函数(表)指针 指向 vftable(表内记录虚函数的地址)

当子类重写父类的虚函数:子类中的虚函数表内部会替换成子类的虚函数地址

当父类的指针或者引用指向子类对象时,发生多态。

多态的优点

  • 代码组织结构清晰
  • 可读性强
  • 利于前期和后期的扩展和维护
  • (开闭原则)
cpp 复制代码
#include <iostream>
#include <string>

using namespace std;
//举例实现一个简易的计算器
class AbstractCalulator
{
public:
	//虚函数
	virtual int getResult()
	{
		return 0;
	}
	int n_number;
	int m_number;
};

class AddCalculator :public AbstractCalulator
{
public:
	int getResult()
	{
		return n_number + m_number;
	}
};

class SubCalculator :public AbstractCalulator
{
public:
	int getResult()
	{
		return n_number - m_number;
	}
};

class MulCalculator :public AbstractCalulator
{
public:
	int getResult()
	{
		return n_number * m_number;
	}
};

void test(void)
{
	AbstractCalulator* abc = new AddCalculator;
	abc->n_number = 10;
	abc->m_number = 10;

	cout << abc->n_number << "+" << abc->m_number << "=" << abc->getResult() << endl;
	delete abc;

	abc = new SubCalculator;
	abc->n_number = 10;
	abc->m_number = 10;

	cout << abc->n_number << "-" << abc->m_number << "=" << abc->getResult() << endl;
	delete abc;

	abc = new MulCalculator;
	abc->n_number = 10;
	abc->m_number = 10;

	cout << abc->n_number << "*" << abc->m_number << "=" << abc->getResult() << endl;
	delete abc;
}

int main(void)
{
	test();
	return 0;
}

纯虚函数和抽象类

在多态中,通常父类中虚函数的实现是毫无意义的,主要是调用子类重写的内容,因此可以将虚函数改为纯虚函数。

纯虚函数语法:virtual 返回值类型 函数名 (参数列表) = 0;

当类中有了纯虚函数,这个类被称为 抽象类

抽象类特点:

  • 无法实例化对象
  • 子类必须重写抽象类中的纯虚函数,否则也属于抽象类
cpp 复制代码
#include <iostream>
#include <string>

using namespace std;

class Base
{
public:
	virtual void func() = 0;

};

class Son:public Base
{
public:
	void func()
	{
		cout << "Son 's func()" << endl;
	}
};

void test(void)
{
	//Base base; 抽象类无法实例化对象
	//new Base;  抽象类无法实例化对象

	Base * base = new Son;
	base->func();
}

int main(void)
{
	test();
	return 0;
}

虚析构和纯虚析构

如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码导致内存泄漏 ,解决办法是将父类的析构函数改为虚析构 或者纯虚析构;

虚析构和纯虚析构的共性:

  • 可以解决父类指针释放子类对象
  • 都需要具体的函数实现

虚析构和纯虚析构的区别:

  • 如果是纯虚析构,该类属于抽象类,无法实例化对象

虚析构语法:virtual ~类名(){}

纯虚析构语法:virtual ~类名() = 0; 类名::~类名(){}

cpp 复制代码
#include <iostream>
#include <string>

using namespace std;

class AbstractAnimal
{
public:
	AbstractAnimal()
	{
		cout << "AbstractAnimal 构造函数调用" << endl;
	}
	//virtual ~AbstractAnimal()
	//{
	//	cout << "AbstractAnimal 析构函数调用" << endl;
	//}
	virtual ~AbstractAnimal() = 0;
	virtual void speak() = 0;
};

AbstractAnimal::~AbstractAnimal()
{
	cout << "AbstractAnimal 析构函数调用" << endl;
}

class Dog :public AbstractAnimal
{
public:
	Dog(string name)
	{
		cout << "Dog 构造函数调用" << endl;
		m_name = new string(name);
	}
	~Dog()
	{
		if (m_name != NULL)
		{
			cout << "Dog 析构函数调用" << endl;
			delete m_name;
			m_name = NULL;
		}
	}
	void speak()
	{
		cout << *m_name << "  Dog speaking" << endl;
	}
	string* m_name;
};

void test(void)
{
	AbstractAnimal* abs = new Dog("Tom");
	abs->speak();
	delete abs;
}

int main(void)
{
	test();
	return 0;
}

推荐文章:C++核心编程(八):类和对象------继承**

相关推荐
砚底藏山河2 分钟前
python量化自定义周期 K 线合成
java·开发语言·数据库·python·金融
IT召唤狮16 分钟前
开源企业级零信任项目Pangolin,零信任能挡住PHP核弹漏洞吗?
开发语言·开源·php
知已难寻16 分钟前
03 · OpenStack的计算管理 Nova
运维·服务器·开发语言·云原生·云计算·openstack·开源软件
Rover Ramble20 分钟前
C++ 用互斥锁实现读写锁
开发语言·c++
你怎么知道我是队长44 分钟前
C++零基础入门第2周:数据类型、运算符与表达式完全指南(附20段可运行代码+避坑清单)
c++
say_fall1 小时前
【Linux系统编程】Ext 文件系统:磁盘与存储、文件与目录、现代计算机究竟如何寻找文件
linux·运维·服务器·数据库·c++
码流子1 小时前
移动收费怎么做?手持终端+App+收费中心的架构实践
java·开发语言·架构
雪落漂泊1 小时前
C++算法 滑动窗口篇(下)
开发语言·c++
云创智城-yuncitys2 小时前
YunParking 4.0:JDK 17 与 Spring Boot 3.2 的停车云升级
java·开发语言·spring boot
郭小李2 小时前
openFeign入门
java·开发语言·前端