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

原创 2016年08月30日 15:51:57

本文以下内容为深度探索c++对象模型的笔记

深度探索c++对象模型是Stanley B Lippman的著作,对c++进行了较深层次的探讨。于我而言,这本书解答了我多年(半年)的疑惑:

虚函数是怎么实现的?

在此分享一二。由于博主本人水平十分有限,因此只能用简单的形式写出来。

虚函数只是c++从语法上支持的规则,概念上讲,任何编译器都可以有自己的实现,这些实现可以各不相同,只要在程序员的角度上看起来相同就可以。无论是哪一种实现,都要从c++的对象模型讲起。Lippman也提到了几种不同的对象模型。比如将类内所有成员都储存在外部,实际只有一个个slot存在于对象之中的简单对象模型;或者是在对象中储存两个指针分别指向数据成员表和成员函数表的表格驱动对象模型。
Lippman着重提到的,便是c++作者当初所设计并仍占有很大优势的对象模型:
非静态数据成员被放在每一个具体的对象之中
静态数据成员则被放在其它地方
静态成员函数和非静态成员函数也被放在其它地方
虚函数以两个步骤支持:
1、每个class产生一堆指向虚函数的指针,放在表格当中,这个表格被称为虚函数表(virtual table)vtbl
2、每个具体的对象之中安插一个指针,指向相关的vtbl。这个指针叫做vptr。vptr的设定和重置由每一个class的构造函数、析构函数、拷贝复制运算符自动完成。每     一个class所关联的type_info object也由vtbl指出,通常放在表格的第一个slot
那么接下来,我会一一解释我自己在阅读《c++ primer》虚函数相关部分时遇到的各种问题:
0、为什么同一个继承体系中的虚函数需要有相同的声明?
因为当编译器遇到一个函数调用时,名称检查是从对象的静态类型开始的。在继承体系中,对于虚函数的使用往往是应用其多态性,也就是通过基类指针或者引用经动态绑定使用派生类中的虚函数版本。由于编译期编译器无法知道一个指针或者引用实际绑定的对象是什么类型,所以才会默认检查其静态类型。既然如此,那么函数的调用形式就必须可以与基类中的某个函数相匹配。换句话说,你调用的所有函数在检查时是一样的,只不过这个函数恰好是虚函数而已。因此,派生类中的虚函数声明才需要基类中一致。
1、为什么虚函数操作要经由指针或者引用完成?
假如不是指针或引用,考虑其形式。类似于
//Derived是Base的派生类
Derived d;
Base b = d;
这时会发生切割现象。我们知道,在这种情况下,对b进行的虚函数调用会调用Base的版本。假设这个d是完完全全地切割并复制给b,那么d的虚函数表应该也会复制给b。那么为什么不会调用Derived的版本呢?当然是因为这并不是完完全全的复制。完完全全,Bitwise copy,即对对象中的每一个位都复制。前面我们说,c++中的拷贝构造函数或者是拷贝赋值运算符都会对vptr进行设定和重置操作。因此,在技术上,这种“现象”是合理的。

问题在于,首先,为什么这里会有一个拷贝函数,其次,为什么Base的拷贝构造函数需要将b的vptr重置成Base的呢,最后,指针或引用跟对象形式有什么根本的不同?

第一个问题需要补充,即在c++里,一个类如果没有定义自己的拷贝构造函数,编译器并不总是会合成一个拷贝构造函数,相反,编译器会直接对新的对象进行逐位复制。有没有一个合成的拷贝构造函数的差别并不是让人很清楚。毕竟拷贝构造函数完成复制的概念深入人心。然而拷贝构造函数的意义就是能够不让类的拷贝出错,因此在拷贝不会出错时,编译器是可以不合成拷贝函数的。(这里讨论的都是没有自定义的拷贝构造函数的时候)
那么第一个问题的答案是:
因为这里有一个虚函数(题设啊题设)。当:
class中含有一个member object而后者有一个拷贝构造函数时(无论是自定义的还是合成的)、class继承自一个拥有拷贝构造函数的基类时、class声明了一个或者多 个虚函数时、class的继承链中有一个或多个虚基类时,编译器才会合成一个拷贝构造函数。
第二个问题的补充是,有权利并不代表一定得这么做。编译器为什么要这么做呢?
虚函数首先要满足多态性,而作为成员函数,派生类中覆盖的虚函数很有可能使用了派生类自己定义的成员。而切割并复制的过程,则是将那些新的成员统统丢弃掉了。使用那些成员将是没有意义的。于是,编译器将vptr重置成了静态类型。
所以第三个问题也就迎刃而解了。无论是指针还是引用,都不会损失对象本身的内存布局。毕竟“指针都是一样的,类型的差别仅仅是解释方式的不同”,而c++的语法设计,又使得基类到派生类的指针能够正确地被使用。

很有趣的一点是,编译器实现,语法,规则。这些什么是因什么是果呢?

第一次写博客好费事啊,就先写到这里吧。

《深度探索C++对象模型》读书笔记——关于对象【for_wind】

//整理之,分享之,欢迎指正。for_wind 1、C与C++的区别:       概括来说,C程序中程序性地使用全局数据[注1]。而C++采用ADT(abstract data tpye)或...
  • for_wind
  • for_wind
  • 2014年03月28日 14:08
  • 1383

深度探索c++对象模型

所谓知己知彼,百战不殆。只有深入了解了c++对象的内存布局,我们才能更熟练运用c++这门语言。 运行环境vs2013一单继承和多继承的结合class C { public: C() :c(1...
  • db199410
  • db199410
  • 2016年06月16日 17:40
  • 372

[读书笔记] 深入探索C++对象模型-第一章《关于对象》

最新在看深入探索C++对象模型(Inside C++ object model),看的同时针对一些之前没有留意或者理解不深的内容整理一下读书笔记,方便之后复习,也希望可以帮助到有同样疑惑的人。 下面是...
  • beyongwang
  • beyongwang
  • 2016年08月21日 21:14
  • 583

深度探索c++对象模型(一)_关于对象

原博客地址:http://www.roading.org//develop/cpp/c对象面面观.html 学习C++应该看过不少关于C与C++的口水贴,以及关于各种对比C与C++效率比较的...
  • A_IIIIIIIII_A
  • A_IIIIIIIII_A
  • 2016年01月04日 11:31
  • 510

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

Lippman早期在贝尔实验室,和C++发明者Bjarne Stroustrup设计了全世界第一套C++编译器cfront,还著有经典的C++入门书[Ensential C++](https://bo...
  • Draco_mystack
  • Draco_mystack
  • 2017年04月18日 22:43
  • 157

《深度探索C++对象模型》:Data语意学

《深度探索C++对象模型》:Data语意学
  • hujingshuang
  • hujingshuang
  • 2016年10月21日 11:34
  • 878

《深度探索C++对象模型》(一)对象模型、存储形式;默认构造函数一定会构造么?

一)、读后感     在我参加工作两年多的时候,工作不算很忙了,《深入理解C++对象模型》开始进入我的视野;或许是因为我要从Symbian.C++ 转向iOS Objective-C,并开始思考语言本...
  • hherima
  • hherima
  • 2013年05月11日 23:02
  • 4185

《深入探索C++对象模型》第三章奇怪语句解释

在第三章的3.3节有下面这样一段描述: class Point3d { private: float x; private: float y; static const int ch...
  • wang1902568721
  • wang1902568721
  • 2016年06月29日 19:38
  • 217

解释:《深度探索C++对象模型》对NRV优化的讨论

原文地址:http://blog.csdn.net/zha_1525515/article/details/7170059 感谢作者! 大纲:  函数返回局部对象的拷贝的一般...
  • lc_910927
  • lc_910927
  • 2014年11月10日 21:52
  • 1071

深度探索C++对象模型-构造函数语义学

default constructor构建 default constructors在编译器需要的时候产生,区别于程序设计者的需要。以下程序进行说明: class A(public: int v;);...
  • isunn
  • isunn
  • 2015年04月19日 17:29
  • 847
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:《深度探索c++对象模型》读书笔记(一)
举报原因:
原因补充:

(最多只允许输入30个字)