C++进阶:多态(一)

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第8天,点击查看活动详情

【写在前面】

本文我们将学习面向对象三大特性中的最后一个特性 —— 多态。需要声明的是,多态一文包括继承一文中所演示的测试用例都是按我的编译器 VS2017 来演示的,我们会演示底层细节,如果你换一个编译器,包括 VS 系列,可能展示出来的效果会有一点变动,因为 C++ 并没有规定具体的实现细节。

一、多态的概念

顾名思义,多态就是多种形态,具体就是去完成某种行为时,不同的对象去完成时会产生不同的状态。

在这里插入图片描述

举个粟子,比如买票这种行为,当普通人去买票时,是全价买票;当学生去买票时,是半价买票;当军人买票时,是优先买票。

再举个粟子,为了争夺在线支持市场,某软件会经常做一些扫码领红包的活动,其中我们会发现,有的人扫到了七八块,有的人扫到了七八角等,其实这背后就是一个多态的行为,它分析你的帐户数据,比如你是第一次扫码,给你 rand() % 99 块、第二次扫码 rand() % 10 块,第三次扫码 rand() % 1 角 ... ...,同样都是扫码动作,不同的用户扫到的红包也不一样,本质也是一种多态行为。

✔ 测试用例一:

#include<iostream>
#include<string>
using namespace std;

class Person
{
public:
	void BuyTicket()
	{
		cout << "正常排队-全价买票" << endl;
	}
protected:
	int _age;
	string _name;
};
class Student : public Person
{
public:
	void BuyTicket()
	{
		cout << "正常排队-半价买票" << endl;
	}
protected:
	//...
};
class Soldier : public Person
{
public:
	void BuyTicket()
	{
		cout << "优先排队-全价买票" << endl;
	}
protected:
	//...
};
void Func(Person* ptr)
{
	ptr->BuyTicket();
}

int main()
{
	Person ps;
	Student st;
	Soldier sd;

	Func(&ps);
	Func(&st);
	Func(&sd);

	return 0;
}
复制代码
  • 怎么让不同的对象都能传给Person* ptr呢 —— 切片,让 Studnet 和 Soldier 继承 Person,但是这里继承之后,基类和派生类中都有 BuyTicket(),那么派生类就会对基类的 BuyTicket() 隐藏。运行程序,可以看到并没有实现多态,都去调用了基类的,这是因为多态的构成需要满足两个条件。

    在这里插入图片描述

二、多态的构成条件

✔ 测试用例二:

#include<iostream>
#include<string>
using namespace std;

class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "正常排队-全价买票" << endl;
	}
protected:
	int _age;
	string _name;
};
class Student : public Person
{
public:
	virtual void BuyTicket()//重写或覆盖父类的虚函数
	{
		cout << "正常排队-半价买票" << endl;
	}
protected:
	//...
};
class Soldier : public Person
{
public:
	virtual void BuyTicket()//重写或覆盖父类的虚函数
	{
		cout << "优先排队-全价买票" << endl;
	}
protected:
	//...
};
void Func(Person* ptr)//指针
{
	//多态 - ptr指向父类对象,调用父类的虚函数;指向子类对象,调用子类的虚函数
	ptr->BuyTicket();
}
void Func(Person& ptr)//引用
{
	//多态 - ptr指向父类对象,调用父类的虚函数;指向子类对象,调用子类的虚函数
	ptr.BuyTicket();
}
//void Func(Person ptr)//对象
//{
//	ptr.BuyTicket();
//}

int main()
{
	Person ps;
	Student st;
	Soldier sd;

	Func(&ps);
	Func(&st);
	Func(&sd);

	Func(ps);
	Func(st);
	Func(sd);

	return 0;
}
复制代码
  • 在继承中要构成多态还有两个条件:a) 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写或覆盖,在继承中我们称这里为隐藏或重定义,注意区分;b) 必须通过基类的指针或者引用调用虚函数,这个条件在测试用例一中就满足了。

    此时就完成了多态,如果没有多态的语法,按以前的理解,这就是调用 Person* 类型的。这里说明以前是跟类型有关,现在是跟对象有关,多态就是让调用跟对象有关,不同的对象去做同一件事,达到的行为是不一样的。

    在这里插入图片描述

  • 注意切片切的是成员变量,与成员函数没有关系,并且这块要实现指向谁调用谁跟切片没有关系,切片只是让父类的指针可以指向子类对象或父类对象,指向子类对象就意味着看到子类对象的那一部分。

  • 多态的两个条件缺一不可,这里可以看到通过基类的对象调用虚函数就不构成多态了,这个问题我们只能先放着,因为这必须了解多态的底层原理才能知晓。

猜你喜欢

转载自juejin.im/post/7127813998904999944