粗略阅读了《深度探索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. nyojb 2357

    http://acm.nyist.me/JudgeOnline/problem.php?id=2357 2357: 插塔憋憋乐 时间限制: 1 Sec  内存限制: 128 MB提交: 50  解决: ...

  2. Hbase 使用方法

    列出所有 table¶ hbase(main):> list 新增 table¶ A . 直接增加一個表 t2 hbase(main):> create 't2' B . 增加一個擁有 ' ...

  3. IntelliJ IDEA配置tomcat【全程详解】

    相关博客:IntelliJ IDEA创建Maven+SSM+Tomcat+Git项目[全程详解] 创建好web项目后,需要将项目部署到Tomcat中运行. 接下来,图文解析IntelliJ IDEA如 ...

  4. redhat linux 中设置网卡固定ip

    更改 /etc/sysconfig/network-scripts/ifcfg-eth0(第一个网卡为eth0) DEVICE=eth0#网卡设备名称 ONBOOT=yes#启动时是否激活 yes | ...

  5. 【Cordova】Cordova开发

    引言 微软开启新战略--移动为先,云为先.作为开发者,首先感受到的变化就是VS2015预览版增加了对各种跨平台框架的支持,极大方便了我们的开发.其中号称原生性能的Xamarin要收费,挺贵的,一般人还 ...

  6. 201621123014《Java程序设计》第十三周学习总结

    1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 为你的系统增加网络功能(购物车.图书馆管理.斗地主等)-分组完成 为了让你的系统可以被多个用户通过网 ...

  7. Mysql系列:高可用(HA)-keeplived

    转自:晓叹星沉 https://my.oschina.net/blueSky4Java/blog/1572905 摘要: 随着项目的发展,为了提高程序的性能,数据库层面或多或少的会用到HA.读写分离. ...

  8. .NET MVC 异步提交和返回参数

    一.后台页面中的接收方法和返回写法 Jsonresult意味着返回值是json格式,也可以是string或者int等其他类型. Httppost代表只接受Post方法. Mvc中返回Jsonresul ...

  9. Java 虚拟机-Java内存区域

    简要介绍Java的内存区域: 运行时数据区域 HotSpot虚拟机对象 一.概览 二.运行时数据区域 2.1 程序计数器 Program Counter Register,代表当前线程所执行的字节码的 ...

  10. 手机访问PC网站自动跳转到手机网站代码(转)

    4G时代,手机网站已经非常普遍了,一般手机网站都有一个二级域名来访问,比如 m.16css.com 如果手机直接访问www.16css.com 就是PC网站,在手机上浏览电脑版网站体验非常不好. 如果 ...