第二十二篇:C++中的多态机制
前言
封装性,继承性,多态性是面向对象语言的三大特性。其中封装,继承好理解,而多态的概念让许多初学者感到困惑。本文将讲述C++中多态的概念以及多态的实现机制。
什么是多态?
多态就是多种形态,就是许多情况下可以互换地使用基类型和派生类型的多种形态。
多态的实现
依赖于动态绑定机制。
动态绑定机制相关
动态绑定是函数实际参数和形式参数绑定的一种方式,它是指我们能够在函数接口中使用继承层次中任意类型的对象,无需关心对象的具体类型。
动态执行接口函数的对象参数的哪个函数得在程序实际执行的时候才能确定
C++中默认不使用动态绑定,要触发动态绑定必须满足两个条件:
1. 接口函数的形式参数必须是引用类型或者指针类型。
2. 动态执行函数(对象参数的成员函数而非接口函数)必须是声明为虚成员函数。
代码实例一
下面代码创建基类对象a,然后创建其派生对象b,当将a,b作为参数传入函数printNum()后,函数让它们分别调用自己的函数getNum():
- #include <iostream>
- using namespace std;
- // 基类
- class A {
- public:
- A() {a=;}
- // **需要动态执行的函数必须声明为虚函数,满足了上条件2。
- virtual int getNum() {
- return a;
- }
- private:
- int a;
- };
- // 派生类
- class B : public A {
- public:
- B() {b=;}
- // 基类中已经声明过为虚函数了不需要再次声明
- int getNum() {
- return b;
- }
- private:
- int b;
- };
- // **接口函数形参声明为引用类型,满足了上条件1。
- void printNum(A & a) {
- // 当实参为基类对象则调用基类对象的getNum,实参为派生类对象则调用派生类对象的getNum。
- cout << a.getNum() << endl;
- }
- int main()
- {
- A a;
- B b;
- printNum(a);
- printNum(b);
- return ;
- }
运行结果:
可以观察到顺利实现了动态绑定,a b分别执行自己的getNum() 函数。
代码实例二
下面代码同样创建基类对象a,然后创建其派生对象b,当将a,b作为参数传入函数printNum()后,函数让它们分别调用自己的函数getNum()(但本例接口函数的形式参数改成了值类型 ):
- #include <iostream>
- using namespace std;
- // 基类
- class A {
- public:
- A() {a=;}
- // **需要动态执行的函数必须声明为虚函数,满足了上条件2。
- virtual int getNum() {
- return a;
- }
- private:
- int a;
- };
- // 派生类
- class B : public A {
- public:
- B() {b=;}
- // 基类中已经声明过为虚函数了不需要再次声明
- int getNum() {
- return b;
- }
- private:
- int b;
- };
- // **接口函数形参声明为值类型,不满足上条件1。
- void printNum(A a) {
- // 未有实现动态绑定,因此不论实参是何种类型,均执行基类的getNum()函数。
- cout << a.getNum() << endl;
- }
- int main()
- {
- A a;
- B b;
- printNum(a);
- printNum(b);
- return ;
- }
运行结果:
可以观察到没有实现动态绑定,a b都执行a的getNum() 函数。这意味着,对象本身并不支持多态,它刚进入函数就被彻底地转换成了形参类型。因此,实现多态要靠的是对象的指针或者引用,而不是对象本身。这也是《C++ Primer》一书中不断强调的东西。
说明
1. 派生类和基类的虚函数类型要一致,只有一种例外 --- 返回对基类类型的引用的虚函数。派生类中的虚函数可以返回基类函数所返回类型的派生类的引用。
2. 基类和派生类的虚函数的默认实参要相同,不然会引起混淆。
小结
封装保证了类的重用( 安全方面 ),继承实现了类的重用,多态则实现了接口的重用。这三个机制体现了C++代码的可重用性,反映了C++在处理大型程序的优势。
第二十二篇:C++中的多态机制的更多相关文章
- Python开发【第二十二篇】:Web框架之Django【进阶】
Python开发[第二十二篇]:Web框架之Django[进阶] 猛击这里:http://www.cnblogs.com/wupeiqi/articles/5246483.html 博客园 首页 ...
- Android UI开发第二十八篇——Fragment中使用左右滑动菜单
Fragment实现了Android UI的分片管理,尤其在平板开发中,好处多多.这一篇将借助Android UI开发第二十六篇——Fragment间的通信. Android UI开发第二十七篇——实 ...
- Python之路【第二十二篇】:Django之Model操作
Django之Model操作 一.字段 AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bi ...
- 【Python之路】第二十二篇--Django【基础篇】
1 Django流程介绍 MTV模式 著名的MVC模式:所谓MVC就是把web应用分为模型(M),控制器(C),视图(V)三层:他们之间以一种插件似的,松耦合的方式连接在一起. 模型负责业 ...
- 第二十二篇:在SOUI中使用代码向窗口中插入子窗口
使用SOUI开发客户端UI程序,通常也推荐使用XML代码来创建窗口,这样创建的窗口使用方便,当窗口大小改变时,内部的子窗口也更容易协同变化. 但是最近不断有网友咨询如何使用代码来创建SOUI子窗口,特 ...
- 【第二十二篇】从客户端中检测到有潜在危险的 Request.Form 值
提交数据的时候 用js的方法 escape(富文本框的值) 例:escape(UM.getEditor('Content').getContent()); 取值的时候 unescape ...
- Python之路(第二十四篇) 面向对象初级:多态、封装
一.多态 多态 多态:一类事物有多种形态,同一种事物的多种形态,动物分为鸡类,猪类.狗类 例子 import abc class H2o(metaclass=abc.ABCMeta): def _ ...
- Python之路(第二十二篇) 面向对象初级:概念、类属性
一.面向对象概念 1. "面向对象(OOP)"是什么? 简单点说,“面向对象”是一种编程范式,而编程范式是按照不同的编程特点总结出来的编程方式.俗话说,条条大路通罗马,也就说我们使 ...
- 第二十二篇、IO多路复用 一
一.简介io多路复用 可以监听多个文件描述符(socket对象)(文件句柄),一旦文件句柄出现变化,就会感知到 Linux中的 select,poll,epoll(内核2.6以上) 都是IO多路复用的 ...
随机推荐
- 转: ios学习入门进阶
著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处.作者:利炳根链接:https://www.zhihu.com/question/19627420/answer/45962351来源 ...
- linux 局域网内文件传送
Linux scp命令用于Linux之间复制文件和目录,具体如何使用这里好好介绍一下,从本地复制到远程.从远程复制到本地是两种使用方式.这里有具体举例: ================== Linu ...
- 【转】Spring Annotation 详解
(1) .<context:component-scan base-package="*.*" /> 该配置隐式注册了多个对注解进行解析的处理器,如: Autowire ...
- LOGO闪光效果
原地址:http://cl314413.blog.163.com/blog/static/1905079762014122105235138/ 这个效果在很多LOGO及广告宣传中都会用到.商业开发的做 ...
- axios 和 vue-axios
1.main.js 全局引入 /** * 引入 axios 数据请求方式 * axios 和 VueAxios 必须同时注入 */ import axios from 'axios' import V ...
- [WebView学习之三]:使用WebView来创建Apps
上一篇我们学习了([WebView学习之二]:使用Web Apps 支持不同分辨率屏),今天我们来继续学习. (博客地址:http://blog.csdn.net/developer_jiangqq) ...
- MySQL 使用 比较函数 INTERVAL() 函数 实现数据按区间分组
首先看一下它的定义: INTERVAL(N,N1,N2,N3,..........) INTERVAL()函数进行比较列表(N1,N2,N3等等)中的N值.该函数如果N<N1返回0,如果N< ...
- MyBatis官方教程及源代码解析——mapper映射文件
缓存 1.官方文档 MyBatis 包括一个非常强大的查询缓存特性,它能够非常方便地配置和定制. MyBatis 3 中的缓存实现的非常多改进都已经实现了,使得它更加强大并且易于配置. 默认情况下是没 ...
- ModelSim高级使用进阶_1_do文件和批处理文件使用_Camp
https://wenku.baidu.com/view/50fb251914791711cc7917fd.html https://wenku.baidu.com/view/73187dcefe47 ...
- centos6安装docker
rpm -ivh http://dl.Fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm rpm --import /etc ...