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++中多态性的一个重要体现,利用基类指针访问派生类中的成员函数,这种情况下使用虚函数,这种情况下采用的是动态绑定技术。
虚函数必须是基类的非静态成员函数,其访问权限可以是protected或public,在基类的类定义中定义虚函数的一般形式:
virtual 函数返回值类型 虚函数名(形参表)
{ 函数体 }
动态绑定:
基类指针是调用派生类的中的成员函数还是调用基类中的成员函数要到程序运行时确定。主要要看指针所指向的对象。
纯虚函数:
纯虚函数是在基类中声明的虚函数,它在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后加“=0”
virtual void funtion1()=0
虚基类、抽象类:
包含纯虚函数的类称为抽象类。由于抽象类包含了没有定义的纯虚函数,所以不能定义抽象类的对象。
虚函数继承:
虚函数继承就是覆盖。即基类中的虚函数被派生类中的同名函数所覆盖。 是实现多态的方法。
虚继承:
解决多重继承中派生类成员函数调用模糊问题。比如类A中有一个函数print(),类B继承A,类C继承A,类D继承类B和类C,这个时候,类D中就有两个print函数,一个是从B继承得到的,一个是从C继承得到的,则类D的对象调用print函数就会出现print模糊的编译错误。解决办法:类B虚拟继承A。类C虚拟继承A,类D继承B,C时,只拷贝A中的数据成员和函数成员一次,再遇到拷贝时候就忽略了!
虚继承就是为了节约内存的,他是多重继承中的特有的概念。适用与菱形继承形式。
如:类B、C都继承类A,D继承类B和C。为了节省内存空间,可以将B、C对A的继承定义为虚拟继承,此时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下载
C++中的继承与虚函数各种概念相关推荐
- C++多继承中重写不同基类中相同原型的虚函数
在C++多继承体系当中,在派生类中可以重写不同基类中的虚函数.下面就是一个例子: class CBaseA { public: virtual void TestA(); }; class ...
- C++对象内存布局--③测试多继承中派生类的虚函数在哪一张虚函数表中
C++对象内存布局--③测试多继承中派生类的虚函数在哪一张虚函数表中 测试2:证明派生类的虚函数的地址跟第一基类的虚函数地址保存在同一张虚函数表中. 派生类有多少个拥有虚函数的基类,派生类对象就有多少 ...
- Visual C++ 2008入门经典 第九章类的继承和虚函数
// 第九章类的继承和虚函数 //.cpp: 主项目文件. //1 继承如何与面向对像的编程思想适应 //2 根据现有类定义新类 //3 使用protected关键字为类成员指定新的访问特性 //4 ...
- C++类内存分布——深度理解继承与虚函数
1.前言与准备 工欲善其事,必先利其器,我们先用好Visual Studio工具,像下面这样一步一步来: 先选择左侧的C/C++->命令行,然后在其他选项这里写上/d1 report ...
- c++虚继承和虚函数和抽象类、接口类,聚合类
虚继承 虚继承用于解决多继承条件下的菱形继承问题(浪费存储空间.存在二义性). 底层实现原理与编译器相关,一般通过虚基类指针和虚基类表实现,每个虚继承的子类都有一个虚基类指针(占用一个指针的存储空间, ...
- C++编程思想:继承与虚函数以及多态
文章目录 简介 实现虚函数多态的技术原理 对象切边 析构函数和构造函数中的虚函数 使用继承的类的析构函数应该使用虚函数修饰符 简介 继承与虚函数与多态是浑然一体的三个概念,父类中虚函数可以表现出多态特 ...
- C++虚继承与虚函数
虚继承和虚函数是完全无相关的两个概念. 虚继承是解决C++多重继承问题的一种手段,从不同途径继承来的同一基类,会在子类中存在多份拷贝.这将存在两个问题:其一,浪费存储空间:第二,存在二义性问题,通常可 ...
- C++,继承、虚函数解惑!
本文作者:sodme 本文出处:http://blog.csdn.net/sodme C++要实现虚函数, 归纳起来, 其实只用干两件事: 1. 根据派生和继承关系, 生成虚函数表; 2. 将代码 ...
- C++继承、虚函数、覆盖、多态、纯虚函数
一.什么是继承 1.当遇到问题时,先查看现有的类能够解决一部分问题,如果有则继承该类,在此类的基础上进行扩展来解决问题,以此可以缩短解决问题的时间(代码复用) 2.当遇到一个大而复杂的问题时,可以先把 ...
最新文章
- python系统-基于Python搭建Django后台管理系统
- ​关于虚拟机迁移文档(p2v v2v
- LeetCode - Medium - Validate IP Addres
- 多类线性分类器算法原理及代码实现 MATLAB
- (转)MVC模式参数传递的探究
- WINDOWS 下 MYSQLQ全库数据倒出和执行计划加入
- linux第一课历史与未来方向
- 视频加密软件技术小分享
- JS反转链表 - I
- 晶振知识,及晶振振荡电路
- 通过追女孩时的常见对话来看你会不会聊天
- 圆点横线圆点 html,目录的点怎么打(目录中小圆点横线上的点要一个个打上去?)...
- Vulkan Cookbook 第七章 1 将GLSL着色器转换为SPIR-V组件
- 新版MacBookPro风扇狂转的问题
- 赵小楼《天道》《遥远的救世主》深度解析(4)从肖亚文引申怎么看待随缘、惜缘、攀缘这三种缘?
- 浙大MPA常规批复试上岸经验分享
- 2022年中国集成电路设计人才需求报告,免费下载
- 哥德巴赫猜想python版
- 华裔科学家张首晟:个人数据完全由个人拥有
- 【面试经典】求解金矿问题(动态规划初级)
热门文章
- 电脑的发展史_互联网发展史 硅谷传奇之 IBM
- 排序算法html,排序算法总结.html
- 反射-获取java私有内部类反射类型、私有字段
- [渝粤教育] 四川农业大学 宏观经济学 参考 资料
- [渝粤教育] 广东-国家-开放大学 21秋期末考试基础会计10258k2
- 【渝粤题库】陕西师范大学202041 国际经济学 作业(专升本)
- spss三次指数平滑_17 统计学:SPSS基础
- android usb触摸屏驱动 win10,Win10手机居然这样兼容安卓:直接运行apk!
- 中文转化成拼音_五笔已经淘汰,拼音到达瓶颈,百度重拳出击,全新输入方式来袭!...
- 小米岭南通服务器维护,小米岭南通交通联合卡内测开启