C++中的继承与虚函数各种概念


 虚继承与一般继承

虚继承和一般的继承不同,一般的继承,在目前大多数的C++编译器实现的对象模型中,派生类对象会直接包含基类对象的字段。而虚继承的情况,派生类对象不会直接包含基类对象的字段,而是通过一个间接的指针去存取基类对象中的字段。

 继承的特性

 继承是面向对象中引入的重要特性之一,它的一个重要的特点就是子类是父类,父类不是子类。也就是说:

    1. 如果基类指针指向子类对象(pbase=&pchild,则该指针只能调用基类定义了的函数;(因为这个地方是静态绑定,而静态绑定所依赖的就是指针声明时的类型)

    2. 如果子类指针指向基类对象(pchild=child *pbase,则会出问题;(因为子类中可能有一些方法是基类中没有的,在编译时静态绑定一些子类中特有的方法可能导致运行时没有这个方法)

    3. 如果基类和子类定义了同名的函数,则到底调用什么函数,必须视该指针的原始类型而定,而不是视指针实际指向的对象类型而定。(这个地方其实就是一般继承和虚函数继承的区别:一般继承静态绑定,所以依据指针声明的原始类型,而虚函数是进行动态绑定的,它是根据实际指针所指向的对象。)

    4. 就算子类继承了父类的某个函数(而未改写它),该函数依然被视为父类的,该函数依然属于父类的域中,该函数中使用的普通函数(非虚函数)依然被视为父类的函数。

    5. 私有变量的继承性:私有变量对子类是不可见的,即使是子类从父类继承下来了,也仍然是不可见的,它仅仅能被父类的函数(没有在子类中改写或重写过的函数)操作。

    6. this指针:类的成员函数的参数中有一个隐藏的参数this指针,这保证了被继承的成员函数归属对象的正确性和无混淆性。

虚函数的实现原理

     正是因为继承的这个特点,虚函数的加入似乎就是顺理成章的事情了。虚函数简化并明确了软件和各种类库的设计以及维护。

    一般的函数在编译链接时就进行了绑定,这称之为早绑定由于信息量不够,所以只能依赖于调用它的对象或指针的声明类型实现绑定。也就是侯俊杰说的,如果基类和子类定义了同名的函数,那么到底调用哪个类的函数,必须视该指针的原始类型而定,而不是视指针实际指向的对象类型而定。因为赋值的动作还没有产生。

    而虚函数则不是这样。虚函数实现的机制是晚绑定,它在编译链接时并没有与某个对象绑定----这也正是虚函数能实现多态(以相同代码调用不同函数)的原因所在。当编译器对程序进行编译碰到虚函数时,将不会赋予一个地址,而是插入一段汇编代码。每个包含虚函数的类都会由编译器产生一个虚函数表和一个虚函数表指针,其中虚函数表指针放在每个类的首地址处(也许不是,不过反正地址偏移量在每个类所占内存中是固定的,这个在其他文章中有专门详述虚函数表)。当程序执行时,碰到对虚函数的调用,则通过插入的汇编代码到当前类的地址中找到虚函数表指针,通过虚函数的序号找到需要调用的虚函数。注意,一个系列的类的虚函数表中某一个函数的序号是一样的。而且,编译器会保证在使用父类指针操作子类对象时只能在父类已有的虚函数上实现虚函数的机制。

    这里还有一个虚函数的默认参数的问题。虚函数是动态绑定的,而默认参数则是静态绑定的,所以在虚函数中使用默认参数可以说是不符合逻辑的。如果子类改写了父类虚函数中的默认参数,当使用多态特性时,会出现调用子类的虚函数,使用的却是父类中的对应虚函数的默认参数的情况。

虚函数适用的两种场合

     1. 某个子类中调用继承下来的非虚函数中有对已改写的虚函数的调用。

    值得注意的是,在某个子类中调用继承下来的未改写的非虚函数中有对已改写的虚函数的调用时,调用的是当前子类中改写过的虚函数;若该非虚函数中有对已改写的非虚函数的调用时,调用的是父类的非虚函数(也是因为晚绑定)。这是MFC的惯用手法。

    2.使用向上映射(父类指针=子类指针),实现代码的重用

    3.父类中的析构函数。当一个类确信不会成为任何类的父类时,它的析构函数是不需要设置成虚函数的;当一个类肯定会成为某个类的父类时,虚析构函数是必要的。因为若是父类中的析构函数是非虚的,则当用一个父类的指向子类的指针delete子类时,这种行为在C++标准中并没有被定义,是十分危险的。

继承中的接口及其实现

   经过以上分析可知,虚函数实际上就是继承中的一种接口。继承中一共有纯虚函数、非纯虚函数和非虚函数三种接口,它们在子类中的处理如下:

    1.纯虚函数:所有子类必须强制性地改写,否则会报错。这是一种仅仅继承接口的方法。

   2.非纯虚函数:又被称为简单虚函数,可以在基类中有自己的实现(默认的动作),子类不一定要改写,这是一种继承接口及其默认实现的方法。

    3.非虚函数:子类最好不要改写,这是一种强制性地继承接口及其实现的方法,表示的是一种共性。

 当在同一个类中存在同名但是参数不同的函数,叫作overloading(重载);子类改写父类的虚函数,叫做overriding(覆盖);子类改写父类的非虚函数,叫做redefining(重定义),这是不推荐的。 

虚函数、纯虚函数、虚基类、抽象类、虚函数继承、虚继承-------各种概念解释

 虚函数:

    虚函数是C++中用于实现多态(polymorphism)的机制。核心理念就是通过基类访问派生类定义的函数。是C++中多态性的一个重要体现,利用基类指针访问派生类中的成员函数,这种情况下使用虚函数,这种情况下采用的是动态绑定技术

    虚函数必须是基类的非静态成员函数,其访问权限可以是protectedpublic,在基类的类定义中定义虚函数的一般形式:

      virtual 函数返回值类型 虚函数名(形参表)

          { 函数体 }

动态绑定:

    基类指针是调用派生类的中的成员函数还是调用基类中的成员函数要到程序运行时确定。主要要看指针所指向的对象。

纯虚函数:

    纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0

              virtual void funtion1()=0

虚基类、抽象类:

    包含纯虚函数的类称为抽象类。由于抽象类包含了没有定义的纯虚函数,所以不能定义抽象类的对象。

虚函数继承:

  虚函数继承就是覆盖。即基类中的虚函数被派生类中的同名函数所覆盖。 是实现多态的方法。

View Code

虚继承:

  解决多重继承中派生类成员函数调用模糊问题。比如类A中有一个函数print(),类B继承A,类C继承A,类D继承类B和类C,这个时候,类D中就有两个print函数,一个是从B继承得到的,一个是从C继承得到的,则类D的对象调用print函数就会出现print模糊的编译错误。解决办法:类B虚拟继承A。类C虚拟继承A,类D继承BC时,只拷贝A中的数据成员和函数成员一次,再遇到拷贝时候就忽略了!

 虚继承就是为了节约内存的,他是多重继承中的特有的概念。适用与菱形继承形式。

 如:类BC都继承类AD继承类BC。为了节省内存空间,可以将BCA的继承定义为虚拟继承,此时A就成了虚拟基类。

  class A;

  class B:public vitual A;

  class C:public vitual A;

  class D:public B,public C;

参考:http://www.haogongju.net/art/1069038

 http://www.diybl.com/course/3_program/c++/cppsl/2008520/117246.html

 一个介绍虚函数的很好的ppt:pdf下载,ppt下载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/351676.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

中国科学院大学数学院本科生教材

中国科学院大学数学科学学院本科生教材(不完全统计) 注:不同的任课老师使用不太一样的教材,仅供参考。 一年级: 微积分I-A:《数学分析(第4版)》第1卷,卓里奇,…

sqlite mysql php_PHP实现的简单操作SQLite数据库类与用法示例

本文实例讲述了PHP实现的简单操作SQLite数据库类与用法。分享给大家供大家参考,具体如下:SQLite是一款轻型的数据库,是遵守ACID的关联式数据库管理系统,它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它…

Win7下WinDbg开启Local Kernel Debug调试

问题:在Win7 64bit系统中用管理员权限打开WinDbg开启Local Kernel Debug时报错: The system does not support local kernel debugging. Local kernel debugging requires Windows XP, Administrative privileges, and is not supported by WOW64. Only …

idea 不能及时编译_您是否能及时编译?

idea 不能及时编译还记得上次被C开发人员嘲笑的时候吗? Java如此繁琐,以至于他们甚至都不会考虑使用这种语言? 在许多方面,这一概念仍然成立。 但是对于典型的用法(在大型企业的骨干中),Java性…

接口开发-导读

接下来的这个系列,完全针对“APP接口”开发进行,所以,希望你有一定的Java开发基础、以及一定的接口交互经验。 思来想去,决定按照下面的提纲进行 1. 基于SpringBoot创建基础框架; 2. 集成数据库操作(mybati…

安装mysql显示有5.0_安装MySQL5.0时到如图这一步提示出错了,~

{"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],"search_count":[{"count_phone":4,"count":4}]},"card":[{"des":"阿里云数据库专家保驾护航,为用户…

WinDbg配置和使用基础

WinDbg是微软发布的一款相当优秀的源码级(source-level)调试工具,可以用于Kernel模式调试和用户模式调试,还可以调试Dump文件。 1. WinDbg介绍: Debugging Tools and Symbols: Getting Started http://www.microsoft.com/whdc/devtools/d…

将Wiremock集成到Spring Boot Java Web应用程序中以模拟外部依赖关系

介绍 WireMock是用于基于HTTP的API的模拟服务器。 有些人可能会将其视为服务虚拟化工具或模拟服务器。 它使您能够存根所需的API或其他外部依赖项,以加快本地开发速度。 它支持测试真实API无法可靠产生的极端情况和失败模式。 在模拟单元测试和集成测试中的外部依赖…

windows下node安装

1.首先到node官网进行下载 下载页面中windows版本分两种,这里我们选择.msi进行安装(.zip是免安装的,但需要单独配置环境变量使用) 2.安装过程如下所示 这里可以更改安装的路径 这里默认会将node和npm加到环境变量中 3.验证安装 安…

tab键的转义字符_Python转义字符及用法

在《Python字符串》一节中我们曾提到过转义字符,就是那些以反斜杠\开头的字符。ASCII 编码为每个字符都分配了唯一的编号,称为编码值。在 Python 中,一个 ASCII 字符除了可以用它的实体(也就是真正的字符)表示,还可以用它的编码值表示。这种使用编码值来间接地表示字符的方…

CentOS中通过NAT连接网络

讲正文之前,推荐一个连接:http://wuxinaiaman928.blog.163.com/blog/static/64932144200811911233198/ 里面比较详细的介绍了Vmware中三种不同的连接方式:桥连接,NAT,使用主机网络,有助于理解简单来讲&…

serialport通过usb通讯_IOT串口通讯-RS232/RS485

串口串口是串行接口(serial port)的简称,也称为串行通信接口或COM接口。串口通信是指采用串行通信协议(serial communication)在一条信号线上将数据一个比特一个比特地逐位进行传输的通信模式。串口按电气标准及协议来划分,包括RS-232-C、RS-422、RS485等…

【项目管理和构建】——Maven下载、安装和配置(二)

版权声明:本文为博主原创文章,未经博主允许不得转载。 目录(?)[] 前言 在上篇博文【项目管理和构建】——Maven简介(一)中我们了解到maven是一种全新的项目构建方式,让我们的开发更加简单,高效。Maven主要做的是两件事…

mapreduce 算法_MapReduce算法–顺序反转

mapreduce 算法这篇文章是介绍MapReduce算法的系列文章的另一部分,该书在使用MapReduce进行数据密集型文本处理中找到。 先前的文章是Local Aggregation , Local Aggregation PartII和创建共现矩阵 。 这次我们将讨论阶数反转模式。 顺序反转模式利用的M…

lamp mysql开启命令_mysql lamp 配置命令总结

[email protected] ~]# chown -R mysql:mysql /usr/local/mysql (注:更改MySQL安装目录属主,属组)[[email protected] mysql-5.5.22]# cp support-files/my-medium.cnf /etc/my.cnf (注:复制MySQL配置文件)[[email protected] mysql-5.5.22]#…

算法复杂度分析(下):最好、最坏、平均、均摊等时间复杂度概述

细化时间复杂度分析 代码千千万,有些代码逻辑会很复杂,所以为了更细化的分析算法的复杂度,再复杂度分析方面引入了4个知识点: 1.最好情况时间复杂度(best case time complexity)。 2.最坏情况时间复杂度&am…

梦想成真…教学–专业的Java开发人员:工具和最佳实践

我总是喜欢分享知识。 我写博客的原因之一是分享我在软件工程师方面的知识。 创立并运行(与几个朋友一起)第一个 早在2003年, 希腊的Java用户组就是由于我们在工作中得不到足够的培训或个人开发机会,因此我们希望共享和重用我们作…

arachni web mysql数据库_Web安全扫描工具Arachni

Arachni是一个多功能、模块化、高性能的Ruby框架,旨在帮助渗透测试人员和管理员评估web应用程序的安全性。同时Arachni开源免费,可安装在windows、linux以及mac系统上,并且可导出评估报告。一、Arachni下载与启动,以LInux环境为例…

tomcat - 报错 No such device; No faulty members identified.

启动tomcat集群的时候出现以下报错,导致集群没办法启动: java.net.SocketException: No such device; No faulty members identified. SEVERE: Unable to start cluster. org.apache.catalina.tribes.ChannelException: java.net.SocketException: No su…

设计模式09----门面设计模式

转自:https://www.cnblogs.com/lthIU/p/5860607.html 针对外观模式,在项目开发和实际运用中十分频繁,但是其极易理解,下面就简要介绍一下。 一、概念介绍 外观模式(Facade),他隐藏了系统的复杂性&#xff0…