探索C++虚函数
探索C++虚函数
1 测试环境
各个编译器对虚函数的实现有各自区别,但原理大致相同。本文基于VS2008探索虚函数
2 测试代码
#pragma once
#include <iostream>
using namespace std;
class C1
{
public:
C1()
{
mem1 = ;
mem2 = ;
}
virtual void f1()
{
cout << "this is C1 f1" << endl;
}
virtual void f2()
{
cout << "this is C1 f2" << endl;
}
virtual ~C1()
{
cout << "this is C1 deconstruction" << endl;
}
int mem1;
int mem2;
}; typedef void (*Fun)(void); //调用虚函数
template<class F>
void CallVirtualFun(const int* p_virTableAddrPtr, const int index)
{
int funAddr = ; //定义函数地址数值,用int取函数地址
int* p_funAddr = NULL; //真实虚函数地址
F fun = NULL; //函数指针 memcpy(&funAddr ,p_virTableAddrPtr + index, ); //从虚函数表中取函数地址,结果保存在funAddr
p_funAddr = (int*)funAddr; //将函数地址数值转换为函数地址
fun = (F)p_funAddr; //转函数指针
fun(); //调用函数
} void VirtualFunByOffset()
{
C1 mC1;
//取出类地址
int* p_classAddr = (int*)(&mC1);
//取出虚表的地址,类的前4个字节是虚表指针,首先取出虚表地址
int virTableAddrInt = *p_classAddr;
//根据虚表的地址访问虚表,虚表每一项都是函数指针,占有4个字节
int* p_virTableAddrPtr = (int*)virTableAddrInt; //将虚函数地址转换为函数指针
CallVirtualFun<Fun>(p_virTableAddrPtr, ); //调用虚函数表的第一个虚函数
CallVirtualFun<Fun>(p_virTableAddrPtr, ); //调用虚函数表的第二个虚函数
};
3 类对象
3.1 虚函数表总是在类对象的起始位置

3.2 虚函数表中函数位置与声明顺序相关
声明虚虚构,看出虚析构函数在虚函数表中第一个位置

将虚析构挪到末尾处声明,看出虚析构在虚函数表末尾位置

3.3 类对象模型
以C1为例,构建对象模型,如下图所示:

- 类对象的最前面为指向虚表的指针(4个字节)
- 虚表的每一项对应类声明的虚函数指针(4个字节),因此,获取虚表的起始地址后,可以根据偏移获取到各个虚函数地址
- 虚函数的指针指向虚函数,只要知道虚函数的格式(声明),就可以调用对应的虚函数
4 代码调试访问虚表
本册测试结构为
首先创建一个类对象,通过类起始地址获取得到类的前4个字节,即虚表地址。

拿到虚表地址后,查看虚表。函数指针每4个字节为1个单位,下面的虚表地址下共有3个虚函数,虚表以0结束。

取得虚表的第一个函数,这里是C1::f1,地址是00 0a 10 c3,访问该地址。并将该地址转换为函数指针:

调用后进入函数体

探索C++虚函数的更多相关文章
- 探索C++虚函数在g++中的实现
本文是我在追查一个诡异core问题的过程中收获的一点心得,把公司项目相关的背景和特定条件去掉后,仅取其中通用的C++虚函数实现部分知识记录于此. 在开始之前,原谅我先借用一张图黑一下C++: “无敌” ...
- 《深度探索C++对象模型》调用虚函数
如果一个类有虚函数,那么这个类的虚函数会被放在一个虚函数表里面, 使用这个类声明的对象中,会有一个指向虚函数表的指针,当使用指向 这个对象的指针或者这个对象的引用调用一个虚函数的时候,就会从虚函数表中 ...
- 【深度探索c++对象模型】Function语义学之虚函数
虚函数的一般实现模型:每一个class有一个virtual table,内含该class中的virtual function的地址,然后每个object有一个vptr,指向virtual table. ...
- 匹夫细说C#:从园友留言到动手实现C#虚函数机制
前言 上一篇文章匹夫通过CIL代码简析了一下C#函数调用的话题.虽然点击进来的童鞋并不如匹夫预料的那么多,但也还是有一些挺有质量的来自园友的回复.这不,就有一个园友提出了这样一个代码,这段代码如果被编 ...
- C++虚函数浅探
C++中和虚函数(Virtual Function)密切相关的概念是"动态绑定"(Dynamic Binding),与之相对的概念是"静态绑定"(Static ...
- C++中为什么要用虚函数、指针或引用才能实现多态?
原文链接:http://blog.csdn.net/zoopang/article/details/14071779 学过C++的都知道,要实现C++的多态性必须要用到虚函数,并且还要使用引用或者指针 ...
- C++虚函数及虚函数表解析
一.背景知识(一些基本概念) 虚函数(Virtual Function):在基类中声明为 virtual 并在一个或多个派生类中被重新定义的成员函数.纯虚函数(Pure Virtual Functio ...
- 【转】C++虚函数解析
本文转自陈皓大叔(左耳朵耗子)的博客www.coolshell.com. 文章是很久之前所写,去年还在写C++时有幸拜读,现在想起来还是相当有价值一转的,如果有一定C++基础(特别是读过<深度探 ...
- [GeekBand] C++继承关系下虚函数内存分布
本文参考文献:GeekBand课堂内容,授课老师:侯捷 :深度探索C++对象模型(侯捷译) :网络资料,如:http://blog.csdn.net/sanfengshou/article/detai ...
随机推荐
- MySQL与Btree
Btree,B+tree,B*tree 前言: 由于在查找中用二分法在查找一些边缘数据时就会产生数据查找不公平,二叉树也存在类似问题:所以就有了B-tree. B+树索引是B+树在数据库中的一种实现, ...
- cmd 运行jar文件
将java工程打成jar包,但第三方jar包并没有包含在包中,当在命令行中运行jar包时,出现类找不到的异常, 在网上看到解决办法是将第三方jar包放到JDK的扩展类文件夹中(%JAVA_HOME%/ ...
- CentOS 6下OpenCV的安装与配置
自己按照网上的教程一步一步来的 http://www.jb51.net/os/RedHat/280309.html 虚拟机环境 CentOS 6.5 内核版本:4.1.14 64位 gcc,gcc 4 ...
- Mac电脑下-nodejs安装卸载升级
一.Mac 安装nodejs: 1:brew install node 2:官网上下载指定版本(.pkg)双击安装 二.Mac 卸载nodejs: 1: brew的安装方式的卸载: brew un ...
- Java io流详解四
转载地址:http://www.cnblogs.com/rollenholt/archive/2011/09/11/2173787.html 写在前面:本文章基本覆盖了java IO的全部内容,jav ...
- android ListView SimpleAdapter 带图片
main.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xml ...
- exec-maven-plugin配置及使用
背景: 如果你想在项maven生命周期内,运行一段java代码,或者一段独立的程序,或者说我们所指的预执行,初始化某些值,生成某些不能预先生成的文件.那么这样我们就可以使用exec-maven-plu ...
- 关于js的异常
遇到异常,通常会有两种处理办法1.处理异常 try{ //可能出现异常的代码 }catch(e){ //处理异常 } 2.抛出异常 public void getName throws Excepti ...
- Druid学习之路 (一)Druid初识
作者:Syn良子 出处:https://www.cnblogs.com/cssdongl/p/9588079.html 转载请注明出处 最近在学习和使用Druid.觉得一些章节有必要按照自己的理解翻译 ...
- javascript对象继承
一.实例化和继承的区别 构造函数.原型和实例的关系:每 个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型 对象的内部指针. 类(Class)和实例(Insta ...