从零开始学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. ...
随机推荐
- MongoDB配置客户端
新建mongodb27017.bat文件 内容为: mongo 127.0.0.1:27017/admin 连接成功! 来自为知笔记(Wiz)
- Oracle数据库“Specified cast is农田valid”
这种错误是笔者在执行一条计算符合条件的行有多少个,用OracleDataReader读取计算出的行数时发生. 查询语句为: Select Count(1) FROM HP_TS Where TS_ID ...
- Quartz.net 2.0的使用说明
Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成,可用于WinForm和ASP.NET应用中.它提供了巨大的灵活性而不牺牲 ...
- delphi 712 Word 2
//导出Wordprocedure TFrm_Computing.ExportWord(aFileName: string; aFileType: string);var wordApp, WordD ...
- cefSharp在XP下使得程序崩溃记录
前言:这是一个奇葩的问题,到现在自己还没有搞明白问题出现在哪里,但是从问题总算是解决了,希望看到此文章的大牛,如果知道问题出在什么地方,可以告知一下. [一个在XP系统下面应用程序崩溃问题] 资源: ...
- 多线程的Python 教程--“贪吃蛇”
本指南的里代码可以在这里下载: threadworms.py ,或者从 GitHub.代码需要 Python 3 或 Python 2 ,同时也需要安装 Pygame . 点击查看大版本图片 ...
- JAVA分析html算法(JAVA网页蜘蛛算法)
近来有些朋友在做蜘蛛算法,或者在网页上面做深度的数据挖掘.但是遇到复杂而繁琐的html页面大家都望而却步.因为很难获取到相应的数据. 最古老的办法的是尝试用正则表达式,估计那么繁琐的东西得不偿失,浪费 ...
- 英语之idiom
1 quick and dirty = Done or constructed in a hasty, approximate, temporarily adequate manner, but no ...
- ubuntu14.04修复启动项
自从安装了ubuntu14.04系统后(win7+ubuntu双系统),一直使用grub来引导win7和ubuntu,很长一段时间都使用的很好.突然前两天win7进不去了,无奈之下就用pe修复了win ...
- 通过扩展让ASP.NET Web API支持JSONP -摘自网络
同源策略(Same Origin Policy)的存在导致了“源”自A的脚本只能操作“同源”页面的DOM,“跨源”操作来源于B的页面将会被拒绝.同源策略以及跨域资源共享在大部分情况下针对的是Ajax请 ...