C++单继承、多继承情况下的虚函数表分析
C++的三大特性之一的多态是基于虚函数实现的,而大部分编译器是采用虚函数表来实现虚函数,虚函数表(VTAB)存在于可执行文件的只读数据段中,指向VTAB的虚表指针(VPTR)是包含在类的每一个实例当中。当使用引用或指针调用虚函数时,首先通过VPTR找到VTAB,然后通过偏移量找到虚函数地址并调用。
本文参考:1.http://blog.lucode.net/programming-language/cpp-vtab-and-call-convention.html
2.https://blog.csdn.net/tangaowen/article/details/5830803
3.《深度探索C++对象模型》
一、单继承
#include<iostream>
#include <stdio.h>
using namespace std;
class A {
public:
void func() {
cout << "A::func()" << endl;
}
virtual void func1() {
cout << "A::func1(): " << endl;
} virtual void func3() {
cout << "A::func3(): " << endl;
}
}; class B: public A {
public:
virtual void func() {
cout << "B::func()" << endl;
}
virtual void vfunc() {
cout << "B::vfunc()" << endl;
}
void func1() {
cout << "B::func1(): " << endl;
}
};
int main() {
typedef void (*Fun)(void);
B a; Fun *fun = NULL;
fun = (Fun*) ((int *) *(int *) &a);
// fun = *(Fun **) &a;
fun[]();
fun[]();
fun[]();
fun[](); return ;
}
运行结果:
B::func1():
A::func3():
B::func()
B::vfunc()
二、多重继承
#include<iostream>
#include <stdio.h>
using namespace std;
class B1 {
public:
virtual void barB1() {cout << "B1::bar" << endl;}
virtual void fooB1() {cout << "B1::foo" << endl;}
}; class B2 {
public:
virtual void barB2() {cout << "B2::bar" << endl;}
virtual void fooB2() {cout << "B2::foo" << endl;}
}; class D : public B1, B2 {
public:
void fooB1() {cout << "D::foo" << endl;}
void barB2() {cout << "D::bar" << endl;}
}; typedef void (*Func)();
int main() {
D tt;
Func* vptr1 = *(Func**)&tt;
Func* vptr2 = *((Func**)&tt + ); vptr1[]();
vptr1[]();
vptr1[]();
cout<<"\\\\\\\\\\\\"<<endl;
vptr2[]();
vptr2[](); return ;
}
运行结果:
B1::bar
D::foo
D::bar
\\\\\\
D::bar
B2::foo
结论:
多重继承会有多个虚函数表,几重继承,就会有几个虚函数表。这些表按照派生的顺序依次排列,如果子类改写了父类的虚函数,那么就会用子类自己的虚函数覆盖虚函数表的相应的位置,如果子类有新的虚函数,那么就添加到第一个虚函数表的末尾。
再简单总结一下 覆盖 隐藏 重载 的区别:
覆盖 是C++虚函数的实现原理,基类的虚函数被子类重写,要求函数参数列表相同;
隐藏 是C++的名字解析过程,分两种情况,基类函数有virtual,参数列表不同,或基类函数没有virtual,无论参数列表是否相同。此时基类指针指向基类实例则调用基类函数,指向子类则调用子类函数。
重载 是在同一命名空间中根据参数对同名函数的区别。
// 我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3ph7kzdx2saoo
C++单继承、多继承情况下的虚函数表分析的更多相关文章
- c++ 继承类强制转换时的虚函数表工作原理
本文通过简单例子说明子类之间发生强制转换时虚函数如何调用,旨在对c++继承中的虚函数表的作用机制有更深入的理解. #include<iostream> using namespace st ...
- C++ 虚函数表解析 继承
C++ 虚函数表解析 陈皓 http://blog.csdn.net/haoel 前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父 ...
- C++ 虚函数表 单继承
本文研究单继承情况下,c++对象的虚函数表的具体情况. 假设有两个类A,B, 其中B由A派生出来,A含有虚函数fun1,B含有虚函数fun2. 测试的代码如下: #include<iostrea ...
- C++多态中虚函数表合并与继承问题
多态: C++的多态是通过一张虚函数表(Virtual Table)来实现的,简称为 V-Table.在这个表中,主要是一个类的虚函数的地址表,这张表解决了继承.覆写的问题,保证其真实反应实际的函数. ...
- C++ 由虚基类 虚继承 虚函数 到 虚函数表
//虚基类:一个类可以在一个类族中既被用作虚基类,也被用作非虚基类. class Base1{ public: Base1(){cout<<"Construct Base1!&q ...
- 详谈C++虚函数表那回事(一般继承关系)
沿途总是会出现关于C++虚函数表的问题,今天做一总结: 1.什么是虚函数表: 虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的.简称为V-Table. ...
- C++ 虚函数表与多态 —— 继承的虚函数表 & 内存布局
1. 使用继承的虚函数表: 如果不涉及多重继承,每个类只有1个虚函数表,当子类继承父类后,子类可以自己改写和新增虚函数,如下图所示: 子类重写 func_1 后,子函数的 func_1 将会有新的逻辑 ...
- 异常情况下的Activity生命周期分析
情况1:资源相关的系统配置发生改变 资源相关的系统配置发生改变,举个栗子.当前Activity处于竖屏状态的时候突然转成横屏,系统配置发生了改变,Activity就会销毁并且重建,其onPause, ...
- C++内存中的封装、继承、多态(下)
上篇讲述了内存中的封装模型,下篇我们讲述一下继承和多态. 二.继承与多态情况下的内存布局 由于继承下的内存布局以及构造过程很多书籍都讲得比较详细,所以这里不细讲.重点讲多态. 继承有以下这几种情况: ...
随机推荐
- 【实战】SpringBoot + KafKa
1.配置pom包 <dependency> <groupId>org.springframework.kafka</groupId> <artifactId& ...
- 委托在Smobiler自定义控件中运用
委托(Delegate) C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针.委托(Delegate) 是存有对某个方法的引用的一种引用类型变量.可以将方法当作另一个方法的参数来进 ...
- IPv6 优于 IPv4 的十大功能
现在是 9102 年,有一个严重的问题,困扰着资深宅男二狗子.那就是偶像团体没新名了.今年开始,偶像团体 XKB48 已经在无法取更多的新名字了,排列组合的所有方式都已经经过了历史长河的洗礼,除非偶像 ...
- 走进python
python史 1.python之父 Guido van Rossum 2.python的优缺点 优点:开发效率高,可跨平台,可嵌入,可扩展,优雅简洁 缺点:运行稍慢,代码不能加密,不能实现真正的多线 ...
- Linux使用httpd配置反代理
Linux安装httpd请看上一篇:https://www.cnblogs.com/tuituji27/p/11189095.html 首先,httpd默认监听端口号是80,增加或修改代理的端口号的文 ...
- 剑指offer第二版-8.二叉树的下一个节点
描述:给定一棵二叉树和其中的一个节点,找出中序遍历序列的下一个节点.树中应定义指向左节点.右节点.父节点的三个变量. 思路: 1.如果输入的当前节点有右孩子,则它的下一个节点即为该右孩子为根节点的子树 ...
- python的@修饰符
‘@’引用已有的函数,对下面的函数进行修饰.引用函数必须放在修饰函数的上面,引用函数的返回值,返回给被修饰的函数 一个简单的栗子: def funA(fn): print('A') # 输出A fn( ...
- LINUX安装源码软件经典三部曲
这几天一直在搞suse下的mplyaer.ffmpeg等源码编译安装,总结出源码软件安装三部曲,网上称为经典三部曲. 这三步分别为: 1. ./configure [options] 2. make ...
- web前端笔试篇(一)
[ 题外话 ]:本博主作为一名准毕业生,即将面临毕业就业问题,即将到大四了,不准备考研的我,那么该去干嘛呢?毫无疑问,那就是实习,那么即使是实习,那么在要想进入自己心仪的企业之前,笔试这一关终究是无法 ...
- 在 .h 和 cpp 中查找 :grep consume ~/test/2016/AMQP-CPP/**/*.cpp ~/test/2016/AMQP-CPP/**/*.h -r
:grep consume ~/test/2016/AMQP-CPP/**/*.cpp ~/test/2016/AMQP-CPP/**/*.h -r -w "whole" 匹配整个 ...