C++ 虚表虚函数怎么就实现了多态?
虚表vftable,编译器为每个拥有虚函数的类都建有一张虚函数表,里面存有虚函数的入口指针(地址)。在类对象的内存布局中,先是一个vfptr虚表指针,指向虚表首地址,而后通过偏移量的形式来访问虚表中的地址。
看许多文章都在那里侃侃而谈,然能实际展示类(对象)内存布局者寥寥,不可见内里实现的终究是借他人文字的空想。now, 我们来一窥究竟!
PS:如何利用VS查看类内存布局见文末链接
1. 带虚函数类内存布局
2. 发生单继承时,派生类内存布局,先是复制一份基类内存布局,然后是自己的布局(注意内存对齐)。虚表指针指向自己的虚表,派生类虚函数地址如果自己未覆盖,那么就是基类的,否则是自己的函数地址。
3. 发生多继承时:先按照继承顺序,从左到右排布基类的布局包括虚标指针,然后排布自己的指针和数据;派生类虚表排布形式是按照继承顺序,是继承来的虚函数,如果有覆盖则换成自己的函数地址;然后是下一个基类,直至基类排布完毕。继承来的多张表是独立的(从内存布局中的多个虚表指针可以看出),且使用首地址+偏移量的形式来访问。
4. 发生虚继承时:无论是对象内存排布还是虚表,虚基类的部分都被放到最后排布,且如果派生类有自己的虚函数则会加在第一个基类的虚表末尾。
除vfptr和vftable之外,增加了vbtable 虚基类表(存放继承的虚基类的地址)和 vbptr(指向虚基类表的指针)
测试代码
#include <iostream>
class Base
{
int a;
int b;
public:
virtual void foo() {};
virtual void bar() {};
virtual void bar2(){};
virtual void bar3(){};
}; class Base2
{
int d;
public:
virtual void foo() {};
}; class Derived : virtual public Base, public Base2
{
int c;
public:
//void foo() {};
void bar() override {};
virtual void bar4() {};
}; int main()
{
Base b;
Derived d;
return ;
}
测试代码
多态原理?个人理解
1. C++多态动态建立在虚函数上,使用virtual关键字指明不要在编译器绑定函数地址,而是在运行时访问虚函数表,即动态绑定。
2. 使用基类指针指向派生类对象且调用虚函数时(前提是派生类覆盖了基类虚函数),运行时该指针指向的地址是派生类对象地址,在派生类对象地址头就是指向虚函数表的vfptr,这张虚表自然是派生类的,而在构造虚表的过程中该虚函数早就被派生类自己的函数地址所覆盖,所以调用函数自然是派生类的函数。
3. 多态的含义:基类指针可以指向基类对象以及不同派生类对象,实现了一种写法,多种访问方式的效果,称为多态。
【参考资料】
如何利用VS查看类内存排布:https://www.cnblogs.com/jerry19880126/p/3616999.html
(在VS项目右键属性->C/C++->命令行->添加 /d1 reportAllClassLayout 应用即可,注意debug/release还有平台类型)
C++多态以及虚函数的不错文章:https://www.cnblogs.com/cxq0017/p/6074247.html
C++ 虚表虚函数怎么就实现了多态?的更多相关文章
- 4.6 C++抽象基类和纯虚成员函数
参考:http://www.weixueyuan.net/view/6376.html 总结: 在C++中,可以通过抽象基类来实现公共接口 纯虚成员函数没有函数体,只有函数声明,在纯虚函数声明结尾加上 ...
- 4.2 C++虚成员函数
参考:http://www.weixueyuan.net/view/6371.html 总结: virtual关键字仅用于函数声明,如果函数是在类外定义,则不需要再加上virtual关键字了. 在C+ ...
- 2014 0416 word清楚项目黑点 输入矩阵 普通继承和虚继承 函数指针实现多态 强弱类型语言
1.word 如何清除项目黑点 选中文字区域,选择开始->样式->全部清除 2.公式编辑器输入矩阵 先输入方括号,接着选择格式->中间对齐,然后点下面红色框里的东西,组后输入数据 ...
- C++学习 - 虚表,虚函数,虚函数表指针学习笔记
http://blog.csdn.net/alps1992/article/details/45052403 虚函数 虚函数就是用virtual来修饰的函数.虚函数是实现C++多态的基础. 虚表 每个 ...
- [转]Java中继承、多态、重载和重写介绍
什么是多态?它的实现机制是什么呢?重载和重写的区别在那里?这就是这一次我们要回顾的四个十分重要的概念:继承.多态.重载和重写. 继承(inheritance) 简单的说,继承就是在一个现有类型的基础上 ...
- 4.5 C++重载、覆盖和遮蔽
参考:http://www.weixueyuan.net/view/6375.html 总结: 函数签名包括函数名和函数参数的个数.顺序以及参数数据类型. 需要注意的是函数签名并不包含函数返回值部分, ...
- C++构造函数中不能调用虚函数
在构造函数中调用虚函数,并不会产生多态的效果,就跟普通函数一样. c++ primer 第四版中497页15.4.5构造函数和析构中的虚函数讲到,如果在构造函数或析构函数中调用虚函数,则运行的是为构造 ...
- C++之虚函数和多态
干货较多-需要自己深思理解: C++支持两种多态性: 1.编译时多态性(静态绑定-早绑定) 在程序编译阶段即可以确定下来的多态性 通过使用 重载机制(重载函数)实现 (模板)http://blog.c ...
- C++学习基础十二——纯虚函数与抽象类
一.C++中纯虚函数与抽象类: 1.含有一个或多个纯虚函数的类成为抽象类,注意此处是纯虚函数,而不是虚函数. 2.如果一个子类继承抽象类,则必须实现父类中的纯虚函数,否则该类也为抽象类. 3.如果一个 ...
随机推荐
- 003——angular 组件 以及组件里面的模板
创建组件: ng g component components/news 一.创建 angualr 组件................................................ ...
- Spring cloud微服务安全实战-4-1章节概述
过渡到复杂的微服务场景下面. 搭建起一个简单的微服务架构,一个网关,一个安全中心,两个微服务,然后会看到如何将安全相关的问题解构出来放在网关上. 然后与OAuth协议整合起来.
- iOS 不允许横屏的简单代码
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWi ...
- pytorch中调整学习率的lr_scheduler机制
有的时候需要我们通过一定机制来调整学习率,这个时候可以借助于torch.optim.lr_scheduler类来进行调整:一般地有下面两种调整策略:(通过两个例子来展示一下) 两种机制:LambdaL ...
- 【物联网】esp8266
esp8266环境配置 https://www.jianshu.com/p/cb0274d612b5 https://www.cnblogs.com/zleiblogs/p/7126106.html ...
- 小程序报错 thirdScriptError
thirdScriptError sdk uncaught third Error Unexpected token export SyntaxError: Unexpected token expo ...
- Sublime Text 3能用支持的插件推荐
从二月份用测试版本build 3012开始用sublime text 3,虽然很多插件在sublime text 3不工作了,因为sublime text 3修复了2的一些bug.提升了性能并集成了不 ...
- 微信小程序 之页面跳转
wxml: <view><button bindtap="abc" >跳转</button></view> js: abc: (e) ...
- C++ 配置文件解析类 ParseConfig
依赖项: 依赖于 ProcessString 类,可从该篇博客获取「字符串处理类 ProcessString (包含常用字符串处理函数)」 ParseConfig.h //Linux & C+ ...
- Python Http-server 使用
Python内置的下载服务器 http.server Python的Web服务器 python2 中SimpleHTTPServer python3 中 http.server 执行 python ...