【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;
}
相关推荐
火山灿火山9 分钟前
Qt常用控件(二)
开发语言·qt
西游音月15 分钟前
(12)功能实现:Qt实战项目之读写配置文件
开发语言·qt
VBA63371 小时前
VBA之Word应用第四章第五节:段落Paragraph对象的属性(一)
开发语言
whltaoin1 小时前
【Java SE】Java IO体系深度剖析:从原理到实战的全方位讲解(包含流操作、序列化与 NIO 优化技巧)
java·开发语言·nio·se·io体系
csbysj20205 小时前
jQuery 删除元素
开发语言
xxy-mm5 小时前
Javascript 中的继承
开发语言·javascript·ecmascript
quikai19817 小时前
python练习第二组
开发语言·python
AI视觉网奇8 小时前
Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr
开发语言·c++·算法
智者知已应修善业8 小时前
【输入两个数字,判断两数相乘是否等于各自逆序数相乘】2023-10-24
c语言·c++·经验分享·笔记·算法·1024程序员节
wjs20248 小时前
并查集快速合并
开发语言