【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;
}
相关推荐
Elihuss2 小时前
ONVIF协议操作摄像头方法
开发语言·php
Swift社区5 小时前
在 Swift 中实现字符串分割问题:以字典中的单词构造句子
开发语言·ios·swift
没头脑的ht5 小时前
Swift内存访问冲突
开发语言·ios·swift
没头脑的ht5 小时前
Swift闭包的本质
开发语言·ios·swift
wjs20245 小时前
Swift 数组
开发语言
xiaoyalian6 小时前
R语言绘图过程中遇到图例的图块中出现字符“a“的解决方法
笔记·r语言·数据可视化
南东山人6 小时前
一文说清:C和C++混合编程
c语言·c++
stm 学习ing6 小时前
FPGA 第十讲 避免latch的产生
c语言·开发语言·单片机·嵌入式硬件·fpga开发·fpga
湫ccc7 小时前
《Python基础》之字符串格式化输出
开发语言·python
Red Red7 小时前
网安基础知识|IDS入侵检测系统|IPS入侵防御系统|堡垒机|VPN|EDR|CC防御|云安全-VDC/VPC|安全服务
网络·笔记·学习·安全·web安全