从零开始学C++之虚函数与多态(一):虚函数表指针、虚析构函数、object slicing与虚函数
一、多态
多态性是面向对象程序设计的重要特征之一。
多态性是指发出同样的消息被不同类型的对象接收时有可能导致完全不同的行为。
多态的实现:
函数重载
运算符重载
模板
虚函数
(1)、静态绑定与动态绑定
静态绑定
绑定过程出现在编译阶段,在编译期就已确定要调用的函数。
动态绑定
绑定过程工作在程序运行时执行,在程序运行时才确定将要调用的函数。
二、虚函数
虚函数的概念:在基类中冠以关键字 virtual 的成员函数
虚函数的定义:
virtual 函数类型 函数名称(参数列表);
如果一个函数在基类中被声明为虚函数,则他在所有派生类中都是虚函数
只有通过基类指针或引用调用虚函数才能引发动态绑定
虚函数不能声明为静态
(1)、虚函数表指针
虚函数的动态绑定是通过虚函数表来实现的。(虚函数表存放虚函数的函数指针)
包含虚函数的类头4个字节存放指向虚函数表的指针
注意:若不是虚函数,一般的函数不会出现在虚函数表,因为不用通过虚函数表指针间接去访问。
|
1 |
#include <iostream>
using namespace std; class Base virtual void Fun3() class Derived : /*virtual */ void Fun3() int main( p = &d; Base &bs = d; d.Fun1(); return |
sizeof(Base); 和 sizeof(Derived); 都是4个字节,其实就是虚表指针,据此可以画出对象的模型:
Derived类继承了Base类的虚函数Fun1,Fun2, 但又重新实现了,即覆盖了。程序中通过基类的指针或引用可以通过vptr间接访问到Derived::Fun1, Derived:::Fun2,但因为Fun3不是虚函数(基类的Fun3 被继承后被隐藏),故p->Fun3(); 和bs.Fun3(); 根据指针或引用的实际类型去访问,即访问到被Derived继承下来的基类Fun3。函数的覆盖与隐藏可以参考这里。
三、虚析构函数
何时需要虚析构函数?
当你可能通过基类指针删除派生类对象时
如果你打算允许其他人通过基类指针调用对象的析构函数(通过delete这样做是正常的),并且被析构的派生类对象是有重要的析构函数需要执行,就需要让基类的析构函数作为虚函数。
|
1 |
#include <iostream>
using namespace std; class Base virtual void Fun3() Base() class Derived : /*virtual */ void Fun3() int main( p->Fun1(); return |
即通过delete 基类指针删除了派生类对象(执行派生类析构函数)。
四、object slicing与虚函数
首先看下图的继承体系:
|
1 |
#include <iostream>
using namespace std; class CObject class CDocument : class CMyDoc : int main( cout << cout << cout << cout << return |
由于Serialize是虚函数,故前3个testing输出都是CMyDoc::Serialize ...但第4个testing中发生了Object Slicing,即对象切割,将CMyDoc对象转换成基类CDocument对象时,调用了CDocument类的拷贝构造函数,CMyDoc类的额外成员如data2_消失,成为完全一个CDocument对象,包括虚表也变成基类的虚表,故输出的是CDocument::Serialize ...
此外还可以看到,调用了两次CDocument构造函数和一次CDocument 拷贝构造函数,CDocument析构函数被调用3次。
参考:
C++ primer 第四版
Effective C++ 3rd
C++编程规范
从零开始学C++之虚函数与多态(一):虚函数表指针、虚析构函数、object slicing与虚函数的更多相关文章
- c++ 虚函数多态、纯虚函数、虚函数表指针、虚基类表指针详解
静态多态.动态多态 静态多态:程序在编译阶段就可以确定调用哪个函数.这种情况叫做静态多态.比如重载,编译器根据传递给函数的参数和函数名决定具体要使用哪一个函数.动态多态:在运行期间才可以确定最终调用的 ...
- C++学习 - 虚表,虚函数,虚函数表指针学习笔记
http://blog.csdn.net/alps1992/article/details/45052403 虚函数 虚函数就是用virtual来修饰的函数.虚函数是实现C++多态的基础. 虚表 每个 ...
- c++基础之虚函数表指针和虚函数表创建时机
虚函数表指针 虚函数表指针随对象走,它发生在对象运行期,当对象创建的时候,虚函数表表指针位于该对象所在内存的最前面. 使用虚函数时,虚函数表指针指向虚函数表中的函数地址即可实现多态. 虚函数表 虚函数 ...
- C++子类虚函数表指针
最近看剑指offer,记录一下 #include <iostream> #include <string> #include <cctype> #include&l ...
- swift class的虚函数表、扩展、@objc修饰、虚函数的派发方式研究
swift class的虚函数表.扩展.@objc修饰的研究 工具: swiftc -emit-sil BaseClass.swift | xcrun swift-demangle > Clas ...
- 从零开始学C++之虚继承和虚函数对C++对象内存模型造成的影响
首先重新回顾一下关于类/对象大小的计算原则: 类大小计算遵循结构体对齐原则 第一个数据成员放在offset为0的位置 其它成员对齐至min(sizeof(member),#pragma pack(n) ...
- C++虚函数实现多态原理(转载)
一.前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有"多种形态 ...
- C++虚函数与多态
C++多态性是通过虚函数来实现的,虚函数允许子类重新定义成员函数,而子类重新定义父类的做法称为覆盖(override),或者称为重写.(这里我觉得要补充,重写的话可以有两种,直接重写成员函数和重写虚函 ...
- C++ 多态、虚函数机制以及虚函数表
1.非virtual函数,调用规则取决于对象的显式类型.例如 A* a = new B(); a->display(); 调用的就是A类中定义的display().和对象本体是B无关系. 2. ...
随机推荐
- NodeJS学习笔记之MongoDB模块
其中还有,nodejs远程连接mysql数据库 一,开篇分析 这篇属于扩展知识篇,因为在下面的文章中会用到数据库操作,所以今天就来说说它(Mongodb模块). (1),简介 MongoDB是一个基于 ...
- [转] C# 键盘中的按键对应的KeyValue
原文C#KeyValue对应键盘 首先先看一下什么情况下需要对按键进行识别: KeyPress事件响应函数中,有KeyPressEventArgs, 对应于e.KeyChar; KeyDown事件响应 ...
- 二级缓存处理大数据 用ehcache.xml配置文件
二级缓存大量数据的解决方案 数据很大 二级缓存 存储大数据,让 内存和磁盘文件进行交互,数据库中的不变的数据在磁盘上,这样就可以少和数据库进行交互了 ehcache.xml 放在src下 <eh ...
- OSX学习01之更新头像
前不久在官网上守株待兔,买了一个官翻版865,其实最想买294的,可是米不足啊——所以,在同时下了865和293的订单,并纠结了一天后,确定了865,剩余的钱够一个Mac mini了,如果不买也可以日 ...
- JavaScript对象(document对象 图片轮播)
图片轮播: 需要注意的HTML需要img标签,他和input标签一样,是非封闭的标签 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Tran ...
- spring BeanFactory概述
BeanFactory是Spring提供的两种容器类型之一,它是基础的IoC容器,并提供完整的IoC服务支持.如果没有指定,默认采用延迟初始化策略.只有当客户端对象需要访问容器中的某个受管对象的时候, ...
- python 安装预编译库注意事项-pip
一般安装依赖库用pip install 库名 就可以,某些情况下依赖的库需要安装预编译好的, 可以参考pip 安装时的错误信息 下面这个链接中可以直接下载 http://www.lfd.uci.edu ...
- 数往知来 SQL SERVER 基本语法<七>
sqlserver学习_01 启动数据库 开始->cmd->进入控制台 sqlcmd->-S .\sqlexpress 1> 如果出现表示数据库"sqle ...
- Visual Basic相关图书推荐
Visual Basic从入门到精通(第2版) 作 者 国家863中部软件孵化器 编 出 版 社 人民邮电出版社 出版时间 2015-03-01 版 次 2 页 数 61 ...
- [转]对Android开发者有益的40条优化建议
下面是开始Android编程的好方法: 找一些与你想做事情类似的代码 调整它,尝试让它做你像做的事情 经历问题 使用StackOverflow解决问题 对每个你像添加的特征重复上述过程.这种方法能够激 ...