深入探索C++对象模型 读书笔记
第1章 关于对象
1、C++在布局以及存取时间上的主要的额外负担是由virtual引起的,包括:a、virtual function机制,引入vptr以及vtbl,支持一个有效率的"执行期绑定"2、"指针的类型"会教导编译器如何解释某个特定地址中的内存内容以及其大小(void*指针只能够持有一个地址,而不能通过它操作所指向的object) 3、C++通过class的pointers和references来支持多态,付出的代价就是额外的间接性。它们之所以支持多态是因为它们并不引发内存中任何"与类型有关的内存委托操作(type-dependent commitment)",会受到改变的,只有他们所指向的内存的"大小和内容的解释方式"而已。 |
第2章
构造函数语意学
第3章
Data语意学
1、类对象大小受三个因素影响a、virtual base和virtual function带来的vptr影响2、Nonstatic data members在class object中的排列顺序将和其被声明顺序一样,任何中间介入的static data members都不会被放进布局之中。 3、静态成员变量 static data members a、存放在程序的data segment之中4、非静态成员变量 nonstatic data members a、 每一个nonstatic data member的偏移量在编译时即可获知 ,不管其有多么复杂的派生,都是一样的。通过对象存取一个nonstatic data member,其效率和存取一个C struct member是一样的。成员变量的具体分布详情参见C++内存分布 |
第4章 Function语意学
1、C++的设计准则之一:nostatic
member function 至少必须和一般的nonmember function有相同的效率。a、改写函数原型,在参数中增加this指针2、覆盖(override)、重写(overload)、隐藏(hide)的区别 3、静态成员函数 static member functions a、不能访问非静态成员4、C++多态(polymorphism)表示"以一个public base class的指针(或者reference),寻址出一个derived class object" 5、vtable虚函数表一定是在编译期间获知的,其函数的个数、位置和地址是固定不变的,完全由编译器掌控,执行期间不允许任何修改。 6、vtable的内容: a、virtual class offset(有虚基类才有)7、执行期虚函数调用步骤 a、通过vptr找到vtbl8、多重继承中,一个派生类会有n-1个额外的vtbl(一个可能有n或者n以上个vtbl,看是否有虚基类),它与第一父类共享vtbl,会修改其他父类的vtbl 9、函数性能 Inline Member > (Nonmember Friend, Static Member, Nonstatic Member) > Virtual Member > Virtual Member(多重继承) > Virtual Member(虚拟继承)10、Inline对编译器只是请求,并非命令。inline中的局部变量+有表达式参数-->大量临时变量-->程序规模暴涨 |
第5章
构造、析构、拷贝语意学
1、析构函数不能定义为纯虚函数,以为每个子类的析构函数都会被编译器扩展调用基类的析构函数以及再上层的基类的析构函数。因为只要缺乏任何一个基类的析构函数的定义,就会导致链接失败。 (实际上纯虚函数是可以被定义以及静态调用-类名::函数,但是C++标准为纯虚函数就是代表没有定义) 2、继承体系下带有数据成员的构造顺序 a、虚基类构造函数,从左到右,从顶层到底层。它和非虚基类不同:是由最底层子类调用的。3、如果类没有定义析构函数,那么只有在类中含有成员对象或者是基类中含有析构函数的情况下,编译器才会自动合成一个出来 4、析构函数的顺序跟构造函数的顺序完全相反,如果是为了多态的析构函数,设置为虚析构函数 5、不要在构造函数和析构函数中调用虚函数 |
第6章
执行期语意学
1、尽量推迟变量定义,避免不必要的构造和析构(虽然C++编译器会尽量保证在调用变量的时候才进行构造,推迟变量定义会使得代码好阅读) 2、全局类变量在编译期间被放置于data段中并被置为0 GOOGLE C++编程规范:3、如果有表达式产生了临时对象,那么应该对完整表达式求值结束之后才摧毁这些创建的临时对象。有两个例外:1)该临时对象被refer为另外一个对象的引用;2)该对象作为另一对象的一部分被使用,而另一对象还没有被释放。 |
第7章
站在对象模型的尖端
1、对于RTTI的支持,在vtbl中增加一个type_info的slot 2、dynamic_cast比static_cast要花费更多的性能(检查RTTI释放匹配、指针offset等),但是安全性更好。 3、对引用施加dynamic_cast:1)成功;或2)抛出bad_cast异常;对指针施加:1)成功;2)返回0指针。 4、使用typeid()进行判断,合法之后再进行dynamic_cast,这样就能够避免对引用操作导致的bad_cast异常: if(typeid(rt) == typeid(rt2)) …。但是如果rt和rt2本身就是合法兼容的话,就会损失了一次typeid的操作性能。 |
posted on 2015-11-20 17:13 zyz913614263 阅读(309) 评论(0) 编辑 收藏 举报