粗略阅读了《深度探索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. 使用 ActiveMQ 创建 Java 应用

    本章重点 Java 应用中内嵌 ActiveMQ 使用 Spring 内嵌 ActiveMQ 创建请求/响应应用 使用 Spring 构建 JMS 客户端

  2. Template、ItemsPanel、ItemContainerStyle、ItemTemplate(包括ListBox的Item子项是横向排列)

    Template.ItemsPanel.ItemContainerStyle.ItemTemplate 分类: WPF2011-10-12 10:13 4716人阅读 评论(0) 收藏 举报 data ...

  3. Generator函数介绍

    Generator函数 基本概念 英文意思为 "生成器". generator函数是es6提供的一种异步编程解决方案,语法行为与传统函数完全不同.从状态上,首先我们把他理解成一种状 ...

  4. 解决:return _compile(pattern, flags).search(string) TypeError: expected string or buffer

    今天写爬虫,爬取MM图片页面的标题时,遇到了一个问题,上图: 看看我的代码: import urllib import urllib2 import re class JPMSG: def __ini ...

  5. 51nod 1099 贪心/思维

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1099 1099 任务执行顺序 基准时间限制:1 秒 空间限制:13107 ...

  6. tableau join 与格式问题

    一开始我没有找到它的join 方法.其实应该是编辑相应的join关系.选择数据源,选择字段.数据源是可以选择的. 剩下的计算问题,要再弄下.不好说,这个其实烦了我很久了. 高级选项,扩展最大行数.即可 ...

  7. 项目管理理论与实践(6)——利用Excel制作项目文档的设计技巧

    这篇是使用的Excel 2007 进行文档设计,Excel的设计也是一门学问,这里主要介绍一些Excel的设计技巧,后面也会陆续更新该文章. 1. 固定某行某列 首先设计这样的任务管理文档: 现在我想 ...

  8. @angular/cli项目构建--http(2)

    客户端GET设置参数查询: search() { const params = new HttpParams() .set('userName', this.userName) .set('fullN ...

  9. New Concept English three (58)

    30w/m 76 errors The old lady was glad to be back at the block of flats where she lived. Her shopping ...

  10. python 编码 —— codecs 库

    1. 对文件读写 import codecs fout = codecs.open('test.html', 'w', encoding='UTF-8') fout.write('<html&g ...