电子工程师技术服务社区
公告
登录
|
注册
首页
技术问答
厂商活动
正点原子
板卡试用
资源库
下载
文章
社区首页
文章
适合具备 C 语言基础的 C++ 教程(七)
分 享
扫描二维码分享
适合具备 C 语言基础的 C++ 教程(七)
C++
wenzi 嵌入式软件
关注
发布时间: 2021-03-02
丨
阅读: 347
# 前言 在前面的教程中,阐述了继承的相关内容,其中就包括继承之后数据成员的访问控制以及多重继承,虚拟继承等内容,本节的内容即将阐述另外一个面向对象的特性:**多态**,多态是面向对象编程三大特性之一。 ## 定义 如何通俗的话来解释多态呢?我们印出来这样一个例子:首先,我们说:人类用手吃饭是本能,而英国人是用刀叉吃饭,中国人则是用筷子吃饭,那现在有一个问题了,当我们问这个人是怎么吃饭的,就不能简单地回答说用筷子或者是用刀叉吃饭,应该根据其所在地国别不同而采用不同的吃饭方式,这就是多态。 ## 代码实现 上述用通俗的话解释了一下,那么现在我们编写具体的代码来实现一下,上述中有人类,有英国人,有中国人,那么我们定义一个`Human`类,然后 `EnglishMan`和`Chinese`都继承自`Human`,代码如下所示: ```cpp class Human { public: void eating(void) {cout << "use hand to eat" << endl;} }; class EnglishMan : public Human { public: void eating(void) {cout << "use knife to eat" << endl;} }; class Chinese : public Human { public: void eating(void) {cout << "use chopsticks to eat" << endl;} }; ``` 紧接着,我们编写一下`test`代码,代码如下所示: ```cpp void test_eating(Human& h) { h.eating(); } ``` 紧接着,我们来编写`main`函数,主函数代码如下所示: ```cpp int main(int argc,char **argv) { Human h; Englishman e; Chinese c; test_eating(h); test_eating(e); test_eating(c); return 0; } ``` 按照常规思路,在调用 `test_eating()`函数的时候,我们传入的实参不同,那么它就会调用不同实参所对应的成员函数,我们看代码的运行结果: ![image-20210220103645630](https://gitee.com/wenzi_D/images4mk/raw/master/image-20210220103645630.png) 可见代码的运行结果并不是如我们所想的一样,那这是为什么呢,这就要提到前面一则教程中所讲的`派生类的空间分布`,也正是因为这个原因,导致代码的运行结果如上图所示,那要如何更改呢,让其按照我们的想法来运行。这里就要提到虚函数的概念了。 ### 虚函数 要实现不同的实参调用不同的方法,我们也可以在`test_eating()`函数里进行判断,然后进行不同方法的调用,当然这是比较笨的方法了,最好的实现方式就是引入虚函数,到底什么是虚函数呢,我们直接看代码: ```cpp class Human { public: virtual void eating(void) {cout << "use hand to eat" << endl;} }; ``` 在 `Human`类的实现里,在成员函数的前面加了`virtual`关键字,则将`eating`函数就变成了虚函数,`Human`的`eating`方法变成了虚函数,那么`EnglishMan`类和`chinese`类的`eating`方法也变成了虚函数。引入了虚函数之后,我们继续执行上述所示的代码,结果如下所示: ![image-20210220105143829](https://gitee.com/wenzi_D/images4mk/raw/master/image-20210220105143829.png) 可见,我们实现了不同的实参调用了不同的方法,回过头来,我们来看最初提出的**多态**的概念,也就与之呼应上了,关于多条总结下来也就是:**使用相同的方法,调用不同类里面的成员函数** 。 **多态**的概念阐述清楚之后,我们继续来剖析虚函数,提到虚函数,必须提及如下两个概念: - 静态联编:非虚函数,在编译的时候就已经确定好何时调用 - 动态联编: - 1、对象里有指针,指向虚函数表 - 2、通过指针,找到虚函数表,进而调用虚函数 **静态联编和动态联编也存在着区别,静态联编效率高,动态联编支持多态**。 简而言之,也就是说一个类里有虚函数,那么这个类的实例化对象中必然存在指针,指针指向虚函数表,通过指针指向的虚函数表调用虚函数,下面是这个过程的一个示意图: ![image-20210220111846577](https://gitee.com/wenzi_D/images4mk/raw/master/image-20210220111846577.png) 为了验证存在虚函数的实例化对象中确实含有一个指针,我们将类的大小打印出来观察。 首先打印没有虚函数的类的大小,我们在`Human`类中加入一个变量: ```cpp class Human { private: int a; public: void eating(void) {cout << "use hand to eat" << endl;} }; ``` 加入了一个数据成员之后,其他的继承方式不改变,我们能编写主函数打印出实例化对象的大小,代码如下所示: ```cpp int main(int argc,char **argv) { Human h; Englishman e; Chinese c; cout<<"sizeof(Human)="<
eating(); delete p[i]; } return 0; } ``` 代码运行的结果如下所示: ![image-20210220170052218](https://gitee.com/wenzi_D/images4mk/raw/master/image-20210220170052218.png) 通过运行结果可知,在执行析构函数的时候,都是执行的`Human`类的析构函数,这样看来并不是正确的,因此也就证实了那句话**析构函数一般声明为虚函数**,更改之后的代码如下所示: ```cpp class Human { private: int a; public: virtual void eating(void) { cout<<"use hand to eat"<
链接:https://pan.baidu.com/s/1xCwpCtqRgfdoeyRICf8WkA > 提取码:ewun
原创作品,未经权利人授权禁止转载。详情见
转载须知
。
举报文章
点赞
(
0
)
wenzi 嵌入式软件
关注
评论
(0)
登录后可评论,请
登录
或
注册
相关文章推荐
MK-米客方德推出工业级存储卡
Beetle ESP32 C3 蓝牙数据收发
Beetle ESP32 C3 wifi联网获取实时天气信息
开箱测评Beetle ESP32-C3 (RISC-V芯片)模块
正点原子数控电源DP100测评
DP100试用评测-----开箱+初体验
Beetle ESP32 C3环境搭建
【花雕体验】16 使用Beetle ESP32 C3控制8X32位WS2812硬屏之二
X
你的打赏是对原创作者最大的认可
请选择打赏IC币的数量,一经提交无法退回 !
100IC币
500IC币
1000IC币
自定义
IC币
确定
X
提交成功 ! 谢谢您的支持
返回
我要举报该内容理由
×
广告及垃圾信息
抄袭或未经授权
其它举报理由
请输入您举报的理由(50字以内)
取消
提交