c++对象模型探索(一)
粗略阅读了《深度探索c++对象模型》一书后,对c++对象底层的内存布局有了一些了解,但同时,也产生了一些疑惑:
1、将子类指针用dynamic_cast转成父类指针之后,其虚表指针会相应变化么?
2、父类转子类呢?
以下是验证疑惑的代码:
#include <iostream>
class A {
public:
virtual void func() {
std::cout << "a: " << a << std::endl;
}
int a = ;
};
class B : public A {
public:
virtual void func() {
std::cout << "b: " << b << std::endl;
}
int b = ;
};
int main() {
A* pa1 = new B();
B* pb1 = (B*)pa1;
B* pb2 = new B();
A* pa2 = dynamic_cast<A*>(pb2);
A* pa3 = new A();
B* pb3 = dynamic_cast<B*>(pa3);
pa1->func();
pb1->func();
pa2->func();
pb2->func();
pa3->func();
pb3->func();
return ;
}
编译:g++ object.cpp -o main --std=c++11 -g
执行结果:
$ ./main
b:
b:
b:
b:
a:
Segmentation fault
在pb3调用func的时候,发生了一个段错误。这个不大符合我的预期,查询了下dynamic_cast的用法,发现:
'dynamic_cast'只用于对象的指针和引用。当用于多态类型时,它允许任意的隐式类型转换以及相反过程。不过,与static_cast不同,在后一种情况里(注:即隐式转换的相反过程),dynamic_cast会检查操作是否有效。也就是说,它会检查转换是否会返回一个被请求的有效的完整对象。
检测在运行时进行。如果被转换的指针不是一个被请求的有效完整的对象指针,返回值为NULL.
如上所说,当dynamic_cast检测到转换不成功的时候,返回的是个NULL指针,因此就不难解释,为什么会发生段错误了。
另外,A* pa2是从B*转换过来的,但其实调用的还是类型B的方法,由此可以推断,类型的虚表指针在类型分配内存的时候就确定了,dynamic_cast的转换并不能将虚表指针重新赋值。
重新调整了下main函数代码:
int main() {
A* pa1 = new B();
B* pb1 = (B*)pa1;
B* pb2 = new B();
A* pa2 = dynamic_cast<A*>(pb2);
A* pa21 = (A*)pb2;
A* pa22 = static_cast<A*>(pb2);
A* pa3 = new A();
B* pb3 = static_cast<B*>(pa3);
pa1->func();
pb1->func();
pb2->func();
pa2->func();
pa21->func();
pa22->func();
pa3->func();
pb3->func();
return ;
}
运行结果如下:
$ ./main
b:
b:
b:
b:
b:
b:
a:
a:
可见,不管是强转、static_cast还是dynamic_cast,都不会影响虚表指针,可以通过GDB来验证下:
(gdb) p *pa1
$ = {_vptr.A = 0x400d10 <vtable for B+>, a = }
(gdb) p *pb1
$ = {<A> = {_vptr.A = 0x400d10 <vtable for B+>, a = }, b = }
(gdb) p *pb2
$ = {<A> = {_vptr.A = 0x400d10 <vtable for B+>, a = }, b = }
(gdb) p *pa2
$ = {_vptr.A = 0x400d10 <vtable for B+>, a = }
(gdb) p *pa21
$ = {_vptr.A = 0x400d10 <vtable for B+>, a = }
(gdb) p *pa22
$ = {_vptr.A = 0x400d10 <vtable for B+>, a = }
(gdb) p *pa3
$ = {_vptr.A = 0x400d30 <vtable for A+>, a = }
(gdb) p *pb3
$ = {<A> = {_vptr.A = 0x400d30 <vtable for A+>, a = }, b = }
可以看到用new B() 方式定义的对象,虚表指针都是指向 B类的虚表指针,用new A()方式定义的对象,虚表指针都指向了A。
由此可以看出,对象的虚表指针,在定义的时候,就确定了,并且不会随着强转、static_cast或dynamic_cast改变。
c++对象模型探索(一)的更多相关文章
- 读书笔记《深度探索c++对象模型》 概述
<深度探索c++对象模型>这本书是我工作一段时间后想更深入了解C++的底层实现知识,如内存布局.模型.内存大小.继承.虚函数表等而阅读的:此外在很多面试或者工作中,对底层的知识的足够了解也 ...
- 柔性数组-读《深度探索C++对象模型》有感 (转载)
最近在看<深度探索C++对象模型>,对于Struct的用法中,发现有一些地方值得我们借鉴的地方,特此和大家分享一下,此间内容包含了网上搜集的一些资料,同时感谢提供这些信息的作者. 原文如下 ...
- 柔性数组-读《深度探索C++对象模型》有感
最近在看<深度探索C++对象模型>,对于Struct的用法中,发现有一些地方值得我们借鉴的地方,特此和大家分享一下,此间内容包含了网上搜集的一些资料,同时感谢提供这些信息的作者. 原文如下 ...
- [读书系列] 深度探索C++对象模型 初读
2012年底-2014年初这段时间主要用C++做手游开发,时隔3年,重新拿起<深度探索C++对象模型>这本书,感觉生疏了很多,如果按前阵子的生疏度来说,现在不借助Visual Studio ...
- 拾遗与填坑《深度探索C++对象模型》3.3节
<深度探索C++对象模型>是一本好书,该书作者也是<C++ Primer>的作者,一位绝对的C++大师.诚然该书中也有多多少少的错误一直为人所诟病,但这仍然不妨碍称其为一本好书 ...
- 拾遗与填坑《深度探索C++对象模型》3.2节
<深度探索C++对象模型>是一本好书,该书作者也是<C++ Primer>的作者,一位绝对的C++大师.诚然该书中也有多多少少的错误一直为人所诟病,但这仍然不妨碍称其为一本好书 ...
- 深度探索C++对象模型
深度探索C++对象模型 什么是C++对象模型: 语言中直接支持面向对象程序设计的部分. 对于各个支持的底层实现机制. 抽象性与实际性之间找出平衡点, 需要知识, 经验以及许多思考. 导读 这本书是C+ ...
- 《深度探索C++对象模型》读书笔记(一)
前言 今年中下旬就要找工作了,我计划从现在就开始准备一些面试中会问到的基础知识,包括C++.操作系统.计算机网络.算法和数据结构等.C++就先从这本<深度探索C++对象模型>开始.不同于& ...
- C++的黑科技(深入探索C++对象模型)
周二面了腾讯,之前只投了TST内推,貌似就是TST面试了 其中有一个问题,“如何产生一个不能被继承的类”,这道题我反反复复只想到,将父类的构造函数私有,让子类不能调用,最后归结出一个单例模式,但面试官 ...
随机推荐
- addslashes及其反函数 stripslashes
addslashes() 函数返回在预定义字符之前添加反斜杠的字符串. stripslashes() 去掉addslashes 所添加的反斜杠 预定义字符是: 单引号(') 双引号(") 反 ...
- Mac的搜狗输入法和QQ输入法加入⌘⌥⌃⇧自定义短语
搜狗输入法(Mac):http://pinyin.sogou.com/mac/ 创建名为『搜狗输入法自定义短语.ini』的文本文件(建议用Sublime Text),内容如下,然后偏好设置的自定义短语 ...
- RK30SDK系统重启源码分析
Linux系统重启的最底层函数是arch_reset,这是一个全局的函数指针变量,定义在 arch/arm/mach-rk30/include/mach/system.h中: extern void ...
- IIFE 立即执行的函数表达式
介绍IIFE IIFE的性能 使用IIFE的好处 IIFE最佳实践 jQuery优化 在Bootstrap源码(具体请看<Bootstrap源码解析>)和其他jQuery插件经常看到如下的 ...
- 神经网络卷积层 要回计算output的维度 input 28 卷积是3x3 则output是26 但是channel是卷积核的数量
model = Sequential() model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=input_s ...
- (转)android头像设置:从本地照片库或拍照获取并剪裁
本文转载于:http://blog.csdn.net/sheeprunning/article/details/9184021 功能介绍 制作android应用时,用户注册的功能必不可少,往往还需要具 ...
- 微服务:Eureka配置集群环境
一.注册中心编码 1.使用idea创建一个spring boot项目,pom如下: <?xml version="1.0" encoding="UTF-8" ...
- Dev c++在新建文件中插入文件头
在菜单栏中依次点击Tools->Editor Options->Snippets->Default Source 勾选Insert the following code into e ...
- php处理redis
1,connect 描述:实例连接到一个Redis.参数:host: string,port: int返回值:BOOL 成功返回:TRUE;失败返回:FALSE 示例: 1 2 3 4 5 <? ...
- 在.net中读写config文件的各种方法(自定义config节点)
http://www.cnblogs.com/fish-li/archive/2011/12/18/2292037.html 阅读目录 开始 config文件 - 自定义配置节点 config文件 - ...