【C++笔记】C++三大特性之多态的概念、定义及使用

1.多态的概念

多态即多种形态,对于C++程序设计中指的是在类的实例化对象中,当不同的对象去完成某个行为时会出现不同的状态。

2.多态的分类

  • 静态的多态:函数重载,看起来调用同一个函数有不同行为。静态:原理是编译时实现。
  • 动态的多态:一个父类的引用或指针去调用同一个函数,传递不同的对象,会调用不同的函数。动态:原理运行时实现。

3.多态的定义

3.1构成多态的两个必要条件!!!

  • 必须通过基类的指针或者引用调用虚函数
  • 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写

3.2虚函数

虚函数:即被virtual修饰的类成员函数称为虚函数。如下示例:

cpp 复制代码
class Person {
public:
	virtual void BuyTicket() { cout << "买票-全价" << endl;}
};

3.3虚函数的重写

派生类中有一个跟基类完全相同的虚函数,即子类中满足三同(函数名、参数、返回值)相同的虚函数,叫做重写(覆盖)

在派生类中虚函数函数重写构成多态的示例及注意事项如下:

cpp 复制代码
class Person {
public:
	virtual void BuyTicket() { cout << "买票-全价" << endl; }
};
class Student : public Person {
public:
/*注意:在重写基类虚函数时,派生类的虚函数在不加virtual关键字时
,虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性)
,但是该种写法不是很规范,不建议这样使用*/
	/*void BuyTicket() { cout << "买票-半价" << endl; }*/
	virtual void BuyTicket() { cout << "买票-半价" << endl; }
};
//1、构成多态,跟p的类型没有关系,传的哪个类型的对象,
//调用的就是这个类型的虚函数 -- 跟对象有关
//2、不构成多态,调用就是p类型的函数 -- 跟类型有关
void Func(Person& p)
{ p.BuyTicket(); }
int main()
{
 	Person ps;
 	Student st;
 	
 	Func(ps);
 	Func(st);
 	return 0;
}

4.虚函数重写的两个例外

4.1协变(基类与派生类虚函数返回值类型不同)。要求返回值是父子关系的指针或者引用

派生类重写基类虚函数时,与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指针或者引用,派生类虚函数返回派生类对象的指针或者引用时,称为协变。

cpp 复制代码
class A{};
class B : public A {};
class Person {
public:
 	virtual A* f() {return new A;}
};
class Student : public Person {
public:
 	virtual B* f() {return new B;}
};

4.2析构函数的重写(基类与派生类析构函数的名字不同)

如果基类的析构函数为虚函数,此时派生类析构函数只要定义,无论是否加virtual关键字,都与基类的析构函数构成重写,虽然基类与派生类析构函数名字不同。虽然函数名不相同,看起来违背了重写的规则,其实不然,这里可以理解为编译器对析构函数的名称做了特殊处理,编译后析构函数的名称统一处理成destructor。

cpp 复制代码
class Person {
public:
 	virtual ~Person() {cout << "~Person()" << endl;}
};
class Student : public Person {
public:
 	virtual ~Student() { cout << "~Student()" << endl; }
};
//只有派生类Student的析构函数重写了Person的析构函数,
//下面的delete对象调用析构函数,才能构成多态,
//才能保证p1和p2指向的对象正确的调用析构函数。
int main()
{
	// 普通对象,析构函数是否虚函数,是否完成重写,都正确调用了
	// Person p;
	// Student s;
	// 动态申请的对象,如果给了父类指针管理,那么需要析构函数是虚函数
	Person* p1 = new Person; // operator new + 构造函数
	Person* p2 = new Student;
	// 虚函数的重写允许,两个都是虚函数或者父类是虚函数,再满足三同,就构成重写。
	// 其实这个是C++不是很规范的地方,当然我们建议两个都写上virtual
	// 本质上,子类重写的虚函数,可以不加virtual是因为析构函数,设计初衷
	// 父类析构函数加上virtual,那么就不存在不构成多态,没调用子类析构函数,内存泄漏场景
	// 建议,我们自己写的时候,都加上virtual,肯定没毛病
	// 析构函数 + operator delete
	//            p1->destructor()   
	delete p1;
	delete p2;
	//            p2->destructor()


	return 0;
}
相关推荐
speop12 分钟前
【笔记】选择题笔记+数据结构笔记
数据结构·笔记
bossface12 分钟前
理解线程库和线程排斥(锁)
linux·运维·服务器·c语言·c++
吃什么芹菜卷21 分钟前
深度学习:卷积神经网络CNN
人工智能·笔记·深度学习·cnn
楠了个难34 分钟前
GPIO之EMIO按键控制LED——ZYNQ学习笔记3
笔记·学习
技术无疆1 小时前
【Python】The Algorithms:开源算法的宝库
java·c语言·开发语言·c++·python·算法·开源
霍格沃兹测试开发学社测试人社区1 小时前
软件测试学习笔记丨Pytest 学习指南
软件测试·笔记·测试开发·学习·pytest
我就是全世界1 小时前
如何用Python监控本股市的方法
开发语言·python·量化系统
OldGj_1 小时前
王道考研视频——操作系统笔记第二章:进程管理
笔记·考研
.别止步春天.1 小时前
Conda 虚拟环境使用指南,python,anaconda,miniconda
开发语言·python·conda
2401_858120531 小时前
MATLAB中的模型预测控制(MPC)实现详解
开发语言·算法·matlab