前言

封装性,继承性,多态性是面向对象语言的三大特性。其中封装,继承好理解,而多态的概念让许多初学者感到困惑。本文将讲述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++中的多态机制的更多相关文章

  1. Python开发【第二十二篇】:Web框架之Django【进阶】

    Python开发[第二十二篇]:Web框架之Django[进阶]   猛击这里:http://www.cnblogs.com/wupeiqi/articles/5246483.html 博客园 首页 ...

  2. Android UI开发第二十八篇——Fragment中使用左右滑动菜单

    Fragment实现了Android UI的分片管理,尤其在平板开发中,好处多多.这一篇将借助Android UI开发第二十六篇——Fragment间的通信. Android UI开发第二十七篇——实 ...

  3. Python之路【第二十二篇】:Django之Model操作

    Django之Model操作   一.字段 AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - bi ...

  4. 【Python之路】第二十二篇--Django【基础篇】

    1 Django流程介绍 MTV模式       著名的MVC模式:所谓MVC就是把web应用分为模型(M),控制器(C),视图(V)三层:他们之间以一种插件似的,松耦合的方式连接在一起. 模型负责业 ...

  5. 第二十二篇:在SOUI中使用代码向窗口中插入子窗口

    使用SOUI开发客户端UI程序,通常也推荐使用XML代码来创建窗口,这样创建的窗口使用方便,当窗口大小改变时,内部的子窗口也更容易协同变化. 但是最近不断有网友咨询如何使用代码来创建SOUI子窗口,特 ...

  6. 【第二十二篇】从客户端中检测到有潜在危险的 Request.Form 值

    提交数据的时候  用js的方法   escape(富文本框的值)    例:escape(UM.getEditor('Content').getContent()); 取值的时候   unescape ...

  7. Python之路(第二十四篇) 面向对象初级:多态、封装

    一.多态 多态 多态:一类事物有多种形态,同一种事物的多种形态,动物分为鸡类,猪类.狗类 例子 import abc class H2o(metaclass=abc.ABCMeta): ​ def _ ...

  8. Python之路(第二十二篇) 面向对象初级:概念、类属性

    一.面向对象概念 1. "面向对象(OOP)"是什么? 简单点说,“面向对象”是一种编程范式,而编程范式是按照不同的编程特点总结出来的编程方式.俗话说,条条大路通罗马,也就说我们使 ...

  9. 第二十二篇、IO多路复用 一

    一.简介io多路复用 可以监听多个文件描述符(socket对象)(文件句柄),一旦文件句柄出现变化,就会感知到 Linux中的 select,poll,epoll(内核2.6以上) 都是IO多路复用的 ...

随机推荐

  1. Spark下载与入门(Spark自学二)

    2.1 下载Spark 略 2.2 Spark中Python和Scala的shell Spark shell可用来与分布式存储在许多机器的内存或者硬盘上的数据进行交互,并且处理过程的分发由Spark自 ...

  2. objc语言的运行时处理

    在Objective-C中,消息是通过objc_msgSend()这个runtime方法及相近的方法来实现的.这个方法需要一个target,selector,还有一些参数.理论上来说,编译器只是把消息 ...

  3. 阿里云ECS linux通过iptables 配置SNAT代理网关,实现局域网上网

    场景说明: 本文将介绍如何通过为VPC中Linux系统的ECS实例配置SNAT,实现无公网ECS通过有EIP的服务器代理访问公网. 步骤: 1.使用SSH的方法登陆一个已经绑定EIP外网的ECS实例. ...

  4. ColorSchemer Studio 2 破解

    软件介绍: ColorSchemer Studio 2 is a professional color matching application for anyone from hobbyists t ...

  5. iOSeasy造成循引用的场景

    场景一 :NStimer timer就是一个能在从如今開始的未来的某一个时刻又或者周期性的运行我们指定的方法的对象 NSTimer运行的必要条件:相应线程的RunLoop要开启,mode要相应 以下看 ...

  6. windows lua 多线程 线程同步

    今天在改一个程序,改成部分逻辑用lua写,这个程序是多线程的.将程序中部分逻辑改成lua之后,各种非法访问内存错误,各种奇奇怪怪的问题,不分时间,不分地点的出现崩溃.从调用堆栈来看,基本都是使用lua ...

  7. JavaScript 事件循环及异步原理(完全指北)

    引言 最近面试被问到,JS 既然是单线程的,为什么可以执行异步操作? 当时脑子蒙了,思维一直被困在 单线程 这个问题上,一直在思考单线程为什么可以额外运行任务,其实在我很早以前写的博客里面有写相关的内 ...

  8. 在连接mysql数据库时出错:The server time zone value '�й���׼ʱ��' is unrecognized or represents more than one time zone

    这个错误是时区导致的,所以需要在配置连接url后面加上时区: url=jdbc:mysql://localhost:3309/test?serverTimezone=UTC 其中UTC是统一标准世界时 ...

  9. 在训练CNN时,loss稳定在log(类别数)

    参见知乎问题! https://www.zhihu.com/question/275774218 很多框架都会有一个问题,当卷积 weight NaN 之后,卷积的 output 会变成 NaN.然后 ...

  10. svn的外网设置访问方法

    一.花生壳 1. 设置静态ip 选择 DHCP服务器 -> 静态地址分配,为内网内的机器分配静态ip 2.设置端口转发 选择 转发规则 -> 虚拟服务器,将外网对443端口的访问转发到安装 ...