参考:http://www.weixueyuan.net/view/6370.html

总结:

  而多态的功能则是将函数名动态绑定到函数入口地址,这样的动态绑定过程称为运行期绑定。

  而在运行期绑定的函数我们称其是多态的。

  通过基类类型的指针根据所指向对象的类型来自动决定调用基类还是派生类的display函数

  要想形成多态必须具备以下三个条件:

  • 必须存在继承关系;
  • 继承关系中必须有同名的虚函数;
  • 存在基类类型的指针或引用,通过该指针或引用调用虚函数。

  

在C++程序中,程序的每一个函数在内存中会被分配一段存储空间,而被分配的存储空间的起始地址则为函数的入口地址。例如我们在设计一个程序时都必须为程序设计一个主函数,主函数同样会在内存中被分配一段存储空间,这段存储空间的起始地址即为函数的入口地址。

在前面的所有列举的程序中,函数的入口地址与函数名是在编译时进行绑定的,我们称之为编译期绑定,而多态的功能则是将函数名动态绑定到函数入口地址,这样的动态绑定过程称为运行期绑定,换句话来说就是函数名与函数入口地址在程序编译时无法绑定到一起,只有等运行的时候才确定函数名与哪一个函数入口绑定到一起。

那么多态到底有什么用处呢?我们不妨来看个例子。在windows操作系统中,我们经常会进行一些关闭操作,比如关闭文件夹、关闭文本文件、关闭播放器窗口等,这些关闭动作对应的函数close假设都继承自同一个基类,但是每一个类都需要有自己的一些特殊功能,比如清理背景、清除缓存等工作,如此一来当我们执行close函数时,我们当然希望根据当前所操作的窗口类型来决定该执行哪一个close函数,因此运行期绑定就可以派上用场了。

编译期绑定是指在程序编译时就将函数名与函数入口地址绑定到一起,运行期绑定是指在程序运行时才将函数名与函数入口地址绑定到一起,而在运行期绑定的函数我们称其是多态的。

为了说明虚函数的必要性,我们先来看一个示例程序。

例1:

#include<iostream>
using namespace std; class base
{
public:
void display(){cout<<"I'm base class!"<<endl;}
}; class derived: public base
{
public:
void display(){cout<<"I'm derived class!"<<endl;} }; int main()
{
base * p;
derived test;
p = &test;
p->display();
return ;
}
这个例子非常简单,两个类,一个是base类,一个是derived类,二者构成继承关系,同时在这两个类中均含有一个display函数,因为函数同名,故在派生类对象中会出现遮蔽现象,即派生类中的display函数会遮蔽基类中的display函数。

在主函数中,定义了一个基类类型的指针p和派生类对象test,之后p指针指向派生类对象test,然后通过指针调用display函数。此程序最终运行结果如下:
    I’m base class!

从结果来看这个程序最终调用的display函数是基类的display函数,而非派生类中的display函数。但此程序的本意是先通过基类类型的指针根据所指向对象的类型来自动决定调用基类还是派生类的display函数。为了实现这样的一种功能,C++提供了多态这一机制。

要想形成多态必须具备以下三个条件:

  • 必须存在继承关系;
  • 继承关系中必须有同名的虚函数;
  • 存在基类类型的指针或引用,通过该指针或引用调用虚函数。

根据这三个条件,我们将例1进行修改,使display函数具有多态特性。修改后程序如例2 所示。

例2:

#include<iostream>
using namespace std; class base
{
public:
virtual void display(){cout<<"I'm base class!"<<endl;}
}; class derived: public base
{
public:
virtual void display(){cout<<"I'm derived class!"<<endl;} }; int main()
{
base * p;
derived test;
p = &test;
p->display();
return ;
}
例2所示程序相对于例1只是在display函数前各添加了一个virtual关键字。我们对照三个多态的构成条件来分析一下,多态首先需要继承关系,derived类继承自base类,因此base类和derived类构成继承关系;其次多态需要同名的虚函数,base类和derived类中都有display函数,同名满足,同时通过添加关键字virtual后,display函数成为虚函数;最后多态需要通过基类类型的指针或引用来调用虚函数,在例2中的主函数中,p即为基类类型指针,并且将该指针指向派生类对象,然后调用display函数。这段程序最终运行结果如下:

I’m derived class!

例2这个程序展示出来的就是多态,display函数通过virtual关键字声明为虚函数,具有多态特性。我们将例2中的主函数修改成以下形式再来分析一下函数运行结果。

int main()
{
base * p = new base;
p->display();
delete p;
p = new derived;
p->display();
delete p;
return ;
}

在这个主函数中同样是声明一个基类类型的指针,之后通过new给指针分配一个基类对象,通过p指针调用display函数,此时不用说肯定是输出“I’m base class!”,因为这中间一直没有涉及到派生类的事情。之后销毁之前new分配的base对象,然后通过new分配一个derived类对象,p指向该派生类对象,通过p指针调用display函数,此时的情况和例2是完全相同的,因此输出“I’m derived class!”,之后再delete销毁派生类对象。修改主函数之后程序输出结果如下:
    I’m base class!
    I’m derived class!

这样的输出结果与我们的分析结果是一致的。

4.1 C++多态的概念及前提条件的更多相关文章

  1. C++学习22 多态的概念及前提条件

    在<C++基类和派生类的赋值>一节中讲到,基类的指针也可以指向派生类对象.请看下面的例子: #include <iostream> using namespace std; c ...

  2. 程序基石系列之C++多态的前提条件

    准备知识 C++中多态(polymorphism)有下面三个前提条件: 必须存在一个继承体系结构. 继承体系结构中的一些类必须具有同名的virtual成员函数(virtualkeyword) 至少有一 ...

  3. JAVA之旅(八)——多态的体现,前提,好处,应用,转型,instanceof,多态中成员变量的特点,多态的案例

    JAVA之旅(八)--多态的体现,前提,好处,应用,转型,instanceof,多态中成员变量的特点,多态的案例 学习是不能停止的 一.多态 我们今天又要学习一个新的概念了,就是多态,它是面向对象的第 ...

  4. C++中多态的概念和意义

    1,函数重写回顾: 1,父类中被重写的函数依然会继承给子类: 2,子类中重写的函数将覆盖父类中的函数: 1,重写父类当中提供的函数是因为父类当中提供的这个函数版本不能满足我们的需求,因此我们要重写: ...

  5. Dataguard配置前提条件

    Data Guard配置前提条件 配置Data Guard必须保证以下前提条件: 1.Data Guard是Oracle企业版的组件.Oracle标准版里没有这个控件.所以Data Guard配置所使 ...

  6. java foreach遍历的前提条件

    自我总结,欢迎拍砖,不胜感激! 目的: 加深foreach遍历的影响 证明:foreach遍历的前提条件是:list !=null ,而不是:list !=null && list.s ...

  7. centos7源码安装Python3的前提条件

    centos7源码安装Python3的前提条件: # yum -y install openssl-devel bzip2-devel expat-devel gdbm-devel readline- ...

  8. 安装爬虫 scrapy 框架前提条件

    安装爬虫 scrapy 框架前提条件 (不然 会 报错) pip install pypiwin32

  9. php接口和多态的概念以及简单应用

    接口是面向对象中的一个重要特性,也是面向对象开发不可缺少的一个概念,下面简单说一下接口的概念,先看一段简单的代码: interface ICanEat { public function eat($f ...

随机推荐

  1. ico 图标 生成 工具 网站

    http://www.faviconico.org/favicon favicon.ico在线制作,在线Favicon.ico制作转换工具

  2. 机器学习与数据科学 基于R的统计学习方法(基础部分)

    1.1 机器学习的分类 监督学习:线性回归或逻辑回归, 非监督学习:是K-均值聚类, 即在数据点集中找出“聚类”. 另一种常用技术叫做主成分分析(PCA) , 用于降维, 算法的评估方法也不尽相同. ...

  3. spring: beanutils.copyproperties将一个对象的数据塞入到另一个对象中(合并对象)

    spring: beanutils.copyproperties将一个对象的数据塞入到另一个对象中(合并对象) 它的出现原因: BeanUtils提供对Java反射和自省API的包装.其主要目的是利用 ...

  4. 雷林鹏分享:jQuery EasyUI 插件

    jQuery EasyUI 插件 jQuery EasyUI 提供了用于创建跨浏览器网页的完整的组件集合,包括功能强大的 datagrid(数据网格).treegrid(树形表格). panel(面板 ...

  5. Linux中符号总结

    常用符号~   登陆用户当前的家目录 .   当前目录..   当前目录的上一级目录cd -   返回上一次的目录;   命令分隔符#   表示注释 ?   通配符中表示任意一个字符*   通配符中表 ...

  6. (转)python 全栈开发,Day74(基于双下划线的跨表查询,聚合查询,分组查询,F查询,Q查询)

    昨日内容回顾 # 一对多的添加方式1(推荐) # book=Book.objects.create(title="水浒传",price=100,pub_date="164 ...

  7. Robbers' watch CodeForces - 685A (暴力)

    大意: 一天n小时, m分钟, 表以7进制显示, 求表显示数字不同的方案数 注意到小时和分钟部分总长不超过7, 可以直接暴力枚举. 关键要特判0, 0的位数要当做1来处理 #include <i ...

  8. 『计算机视觉』各种Normalization层辨析

    『教程』Batch Normalization 层介绍 知乎:详解深度学习中的Normalization,BN/LN/WN 一.两个概念 独立同分布(independent and identical ...

  9. 第一阶段——站立会议总结DAY01

    1.昨天做了什么:无 2.今天准备做什么:准备开始做个人中心界面,首先是创建页面 3.遇到的困难:“无从下手”,怕写完某个界面之后就会找不到相关的名字接口什么的.

  10. tomcat8 tomcat-users相关配置

    第一步:修改账号密码 vim conf/tomcat-users.xml <role rolename="manager-gui"/> <role rolenam ...