粗略阅读了《深度探索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++对象模型探索(一)的更多相关文章

  1. 读书笔记《深度探索c++对象模型》 概述

    <深度探索c++对象模型>这本书是我工作一段时间后想更深入了解C++的底层实现知识,如内存布局.模型.内存大小.继承.虚函数表等而阅读的:此外在很多面试或者工作中,对底层的知识的足够了解也 ...

  2. 柔性数组-读《深度探索C++对象模型》有感 (转载)

    最近在看<深度探索C++对象模型>,对于Struct的用法中,发现有一些地方值得我们借鉴的地方,特此和大家分享一下,此间内容包含了网上搜集的一些资料,同时感谢提供这些信息的作者. 原文如下 ...

  3. 柔性数组-读《深度探索C++对象模型》有感

    最近在看<深度探索C++对象模型>,对于Struct的用法中,发现有一些地方值得我们借鉴的地方,特此和大家分享一下,此间内容包含了网上搜集的一些资料,同时感谢提供这些信息的作者. 原文如下 ...

  4. [读书系列] 深度探索C++对象模型 初读

    2012年底-2014年初这段时间主要用C++做手游开发,时隔3年,重新拿起<深度探索C++对象模型>这本书,感觉生疏了很多,如果按前阵子的生疏度来说,现在不借助Visual Studio ...

  5. 拾遗与填坑《深度探索C++对象模型》3.3节

    <深度探索C++对象模型>是一本好书,该书作者也是<C++ Primer>的作者,一位绝对的C++大师.诚然该书中也有多多少少的错误一直为人所诟病,但这仍然不妨碍称其为一本好书 ...

  6. 拾遗与填坑《深度探索C++对象模型》3.2节

    <深度探索C++对象模型>是一本好书,该书作者也是<C++ Primer>的作者,一位绝对的C++大师.诚然该书中也有多多少少的错误一直为人所诟病,但这仍然不妨碍称其为一本好书 ...

  7. 深度探索C++对象模型

    深度探索C++对象模型 什么是C++对象模型: 语言中直接支持面向对象程序设计的部分. 对于各个支持的底层实现机制. 抽象性与实际性之间找出平衡点, 需要知识, 经验以及许多思考. 导读 这本书是C+ ...

  8. 《深度探索C++对象模型》读书笔记(一)

    前言 今年中下旬就要找工作了,我计划从现在就开始准备一些面试中会问到的基础知识,包括C++.操作系统.计算机网络.算法和数据结构等.C++就先从这本<深度探索C++对象模型>开始.不同于& ...

  9. C++的黑科技(深入探索C++对象模型)

    周二面了腾讯,之前只投了TST内推,貌似就是TST面试了 其中有一个问题,“如何产生一个不能被继承的类”,这道题我反反复复只想到,将父类的构造函数私有,让子类不能调用,最后归结出一个单例模式,但面试官 ...

随机推荐

  1. 如何激活Windows10系统

    Win10正式企业版系统的激活方法: 按住 win+x 就会出现如下,右击桌面的左下角的“Windows”图标,从其右键菜单中选择“命令提示符(管理员)”项,以便打开 MSDOS界面.   待打开MS ...

  2. Android中播放DSD音乐

    Github上有个简单的Alsa DSD测试程序,可以播放DSD,地址位于:https://github.com/zonque/alsa-dsd-player 细看其代码,发现有ALSA_FORMAT ...

  3. 【VS2013编译DirectX Tutorials时遇到的错误】FXC : error X3501: 'main': entrypoint not found

    修改于2015年9月6日: 去年写这篇解决方案的时候其实对着色器编程还一知半解,摸索了一个治标不治本的方法解决问题,结果被一个CSDN的博主原封不动抄了去,还打上个原创的标签= =,简直无语... 最 ...

  4. oracle decode函数 和 case when

    1.oracle decode分支函数 select decode(to_char(B.LQSJ, 'hh24:mi:ss'), '00:00:00', to_char(B.LQSJ, 'yyyy-m ...

  5. 16_游戏编程模式ServiceLocator 服务定位

    ####简单说,就是某个系统作为一个服务,对全局系统可见. Service Locator (服务定位) ``` //简单粗暴的代码, 使用声音系统 // Use a static class? Au ...

  6. 1117. Eddington Number(25)

    British astronomer Eddington liked to ride a bike. It is said that in order to show off his skill, h ...

  7. Jtable实现

    package database; import java.util.Vector; import javax.swing.table.AbstractTableModel; public class ...

  8. 下载安装tomcat至服务器

    1.安装JDK之后,下载Tomcat:http://tomcat.apache.org/download-70.cgi选择下载32-bit/64-bit Windows Service Install ...

  9. python 图形化(Tkinter)

    python提供了多个图形开发界面的库,几个常用Python GUI库如下: Tkinter: Tkinter模块("Tk 接口")是Python的标准Tk GUI工具包的接口.T ...

  10. 洛谷 4245 【模板】任意模数NTT——三模数NTT / 拆系数FFT

    题目:https://www.luogu.org/problemnew/show/P4245 三模数NTT: 大概是用3个模数分别做一遍,用中国剩余定理合并. 前两个合并起来变成一个 long lon ...