《深度探索c++对象模型》 学习笔记 - 4 Function语义学
2009-02-19 10:35
155 查看
4 Function语义学
1. C++标准要求:非静态成员函数至少必须和一般的非成员函数有相同的效率。
2. 成员函数会被编译器mangle为非成员函数,尤其是重载更需要mangle手法进行改名。extern “C”阻止函数改名。
3. Static成员函数:1)参数没有this;2)不能访问非静态成员;3)不能是const、virtual等;4)可以不用对象访问。
4. Static成员函数,由于没有this,所以可以作为callback函数的候选,或者作为线程的主函数。
5. C++中多态表示:以一个public base class的指针或引用,寻址出一个derived class对象,并访问相应的virtual函数。
6. Vtbl中的虚函数一定在编译期间获知,其函数的个数、位置和地址是固定不变的,执行期间不能增、改、删。
7. 执行期三步完成虚函数调用:1)由vptr找到vtbl;2)定位vtbl中的slot(索引值);3)通过该索引下的值调函数。
8. Vtbl的内容包括三部分:1)在该类中定义的函数实体,它是一个新的virtual函数,或者会override其基类的虚函数;2)继承自基类的虚函数实现,本类不进行override;3)纯虚函数的占位。注意:普通非virtual函数不在vtbl中。
9. 子类新增加virtual函数的时候,会在原本的vtbl中最后面增加一个slot,加入这个新的virtual函数地址。
10. 多重继承中,一个派生类会有n-1个额外vtbl(n=直接基类个数),它与第一父类共享vtbl,会修改其他父类的vtbl。
11. 在这三种情况下,第二或后继基类会影响virtual函数的调用:
Ø 通过“指向第二个基类”的指针,调用派生类的自己新的虚函数。这时,指针必须调整到Derived的vptr处。
Ø 通过“指向派生类”的指针,调用从第二个基类中派生下来的虚函数。这时,指针必须调整到第二基类vptr处。
Ø 允许从基类派生的虚函数修改返回值的情况,在VC中不支持,所以具体情况未知。
12. 虚拟继承下的虚函数,由于有了一个到虚拟基类的offset,所以virtual函数的调用复杂度更高,性能更差。
13. A)指向非static成员变量的指针,其值是它在该类内存中的offset:float ClassA::*pt1 = &ClassA::m_f1;B)1)指向静态成员函数的指针,其值是该函数在内存中的真正地址;2)指向virtual成员函数的指针,其值是vtbl中的索引值;3)指向非virtual非静态成员函数的指针,其值是该函数在内存中的真正地址,绑定到this之后即可以进行函数调用。
Inline对编译器只是请求,并非命令。inline中的局部变量+有表达式的参数 => 大量临时变量 => 程序规模暴涨。
实验代码:
1. C++标准要求:非静态成员函数至少必须和一般的非成员函数有相同的效率。
2. 成员函数会被编译器mangle为非成员函数,尤其是重载更需要mangle手法进行改名。extern “C”阻止函数改名。
3. Static成员函数:1)参数没有this;2)不能访问非静态成员;3)不能是const、virtual等;4)可以不用对象访问。
4. Static成员函数,由于没有this,所以可以作为callback函数的候选,或者作为线程的主函数。
5. C++中多态表示:以一个public base class的指针或引用,寻址出一个derived class对象,并访问相应的virtual函数。
6. Vtbl中的虚函数一定在编译期间获知,其函数的个数、位置和地址是固定不变的,执行期间不能增、改、删。
7. 执行期三步完成虚函数调用:1)由vptr找到vtbl;2)定位vtbl中的slot(索引值);3)通过该索引下的值调函数。
8. Vtbl的内容包括三部分:1)在该类中定义的函数实体,它是一个新的virtual函数,或者会override其基类的虚函数;2)继承自基类的虚函数实现,本类不进行override;3)纯虚函数的占位。注意:普通非virtual函数不在vtbl中。
9. 子类新增加virtual函数的时候,会在原本的vtbl中最后面增加一个slot,加入这个新的virtual函数地址。
10. 多重继承中,一个派生类会有n-1个额外vtbl(n=直接基类个数),它与第一父类共享vtbl,会修改其他父类的vtbl。
11. 在这三种情况下,第二或后继基类会影响virtual函数的调用:
Ø 通过“指向第二个基类”的指针,调用派生类的自己新的虚函数。这时,指针必须调整到Derived的vptr处。
Ø 通过“指向派生类”的指针,调用从第二个基类中派生下来的虚函数。这时,指针必须调整到第二基类vptr处。
Ø 允许从基类派生的虚函数修改返回值的情况,在VC中不支持,所以具体情况未知。
12. 虚拟继承下的虚函数,由于有了一个到虚拟基类的offset,所以virtual函数的调用复杂度更高,性能更差。
13. A)指向非static成员变量的指针,其值是它在该类内存中的offset:float ClassA::*pt1 = &ClassA::m_f1;B)1)指向静态成员函数的指针,其值是该函数在内存中的真正地址;2)指向virtual成员函数的指针,其值是vtbl中的索引值;3)指向非virtual非静态成员函数的指针,其值是该函数在内存中的真正地址,绑定到this之后即可以进行函数调用。
Inline对编译器只是请求,并非命令。inline中的局部变量+有表达式的参数 => 大量临时变量 => 程序规模暴涨。
实验代码:
#ifndef ch4_h #define ch4_h namespace ch4{ // Data semantic // p145 namespace nameMangle{ // 关于mangling和extern "C" // No1和No2可以永远共存,并可以和No3或No4共存 // No3和No4不能共存,因为: // error C2733: second C linkage of overloaded function 'f1' not allowed // 就是说,作为C语言的函数,不能重载。 // 但是奇怪的是,No3和No1就不算重载吗? // A:应该算重载,但是No1改了名字而No3没有改,所以没问题 int f1(){return 1;}; // NO1 int f1(int){return 1;}; // NO2 extern "C" int f1(double){return 1;}; // NO3 // extern "C" int f1(char){return 1;}; // NO4 class ccclass{ public: // 在类的里面不能使用extern "C"来阻止name mangling // extern "C" int x(){ return 0;}; int y(){return 1;}; }; void test(){ int n = f1(); n = f1(10); n = f1(.1); } } // p165 namespace vtable{ // 根据看Derived的类中的两个vptr(Base1带来一个,Base2带来一个) // 发现其vtbl的构造,与书上所说不一样,书上的部分肯定有错误,尤其是 // Base1::vtbl中居然有Base2::mumble,简直不可能。 // 正确结果如下(太明显了,就不解释了;typeid没有显示出来): /* - ch4::vtable::Base1 {...} - __vfptr 0x0042a2b0 const ch4::vtable::Derived::`vftable'{for `ch4::vtable::Base1'} [0] 0x004011d1 ch4::vtable::Derived::`scalar deleting destructor'(unsigned int) [1] 0x004011e5 ch4::vtable::Base1::speakClearly(void) [2] 0x00401226 ch4::vtable::Derived::clone1(void) - ch4::vtable::Base2 {...} - __vfptr 0x0042a158 const ch4::vtable::Derived::`vftable'{for `ch4::vtable::Base2'} [0] 0x004011d6 [thunk]:ch4::vtable::Derived::`vector deleting destructor'`adjustor{8}' (unsigned int) [1] 0x0040120d ch4::vtable::Base2::mumble(void) [2] 0x00401221 ch4::vtable::Derived::clone2(void) */ class Base1{ public: Base1(){}; virtual ~Base1(){}; virtual void speakClearly(){}; virtual void clone1() const{}; int m_base1; }; class Base2{ public: Base2(){}; virtual ~Base2(){}; virtual void mumble(){}; virtual void clone2() const{}; int m_base2; }; class Derived: public Base1, public Base2 { public: Derived(){}; virtual ~Derived(){}; virtual void clone1() const{}; virtual void clone2() const{}; int m_Derived2; }; void test(){ Derived d; } } // 第三章的p130: 指向数据成员的指针。可以用来研究内存布局 // 本来应该放到第三章,但是第四章有非常详细的说明,所以就写到一起了。 namespace point2d3d{ // 内存布局: // vptr(4),x(4),y(4) class p2d{ public: int x; int y; virtual void f(){}; }; // 内存布局: // vptr(4), next(4), p2d[vptr(4),x(4),y(4)] // 对于virtual继承,子类和基类共享同一个vptr, // 不过,由于有了offset pointer,这样就增加了size; class vertex:public virtual p2d{ public: vertex* next; }; // 内存布局,同vertex: // vptr(4), z(4), p2d[vptr(4),x(4),y(4)] class p3d:public virtual p2d{ public: int z; }; // 内存布局:vertex + p3d - p2d // vertex[vptr(4), next(4)], p3d[vptr(4), z(4)], dummy(4), p2d[vptr(4),x(4),y(4)] // 对于普通继承,子类会和基类共享同一个vptr,换句话说,不会由于virtual func而增加size; class pointvertex3d:public vertex, public p3d { public: int dummy; }; void test() { // 指向数据成员的指针,其值是该对象(变量)在class object中的内存地址位置偏移量, // 由于都是int、*、vptr等,所以,下面的值都是0,4,8等,4的倍数 int p2d::*n = 0; n = &p2d::x; n = &p2d::y; int p3d::*n2 = 0; n2 = &p3d::x; n2 = &p3d::y; n2 = &p3d::z; int vertex::*n3 = 0; n3 = &vertex::x; n3 = &vertex::y; vertex* vertex::*nv = 0; nv = &vertex::next; int pointvertex3d::*n4 = 0; n4 = &pointvertex3d::x; n4 = &pointvertex3d::y; n4 = &pointvertex3d::z; n4 = &pointvertex3d::dummy; vertex* pointvertex3d::*nv2 = 0; nv2 = &pointvertex3d::next; // 输出函数指针,用%p printf("pointvertex3d::next: %p", nv2); } } // main test void test(){ printf("ch4 begin/n"); nameMangle::test(); vtable::test(); point2d3d::test(); printf("ch4 end/n"); } }; #endif
相关文章推荐
- 《深度探索c++对象模型》学习笔记 - 6 执行期语义学
- 《深度探索c++对象模型》 学习笔记 - 5 构造、析构、拷贝 语义学
- c++学习笔记——虚函数(virtual function)
- lua学习笔记之Lua的function、closure和upvalue
- [TensorFlow 学习笔记-06]激活函数(Activation Function)
- python学习手册笔记--第16~19章--function_base
- Inside the C++ Object Model 学习笔记 第六章 执行期语义学
- 台湾大学林轩田机器学习技法课程学习笔记14 -- Radial Basis Function Network
- function-like classes 仿函数笔记----C++学习之路
- php引用返回function & fun();学习笔记
- c++ primer 学习笔记(2): 函数 function
- JAVA8学习笔记-function
- 《深度探索C++对象模型》第五章Semantics of Construction,Destruction, and Copy_学习笔记
- 源代码学习笔记之Function
- 《深度探索c++对象模型》学习笔记 - 附录
- 《深度探索C++对象模型》笔记——Function语意学
- 概率图模型(PGM)学习笔记(二)贝叶斯网络-语义学与因子分解
- JavaScript学习笔记之Function对象
- 《深度探索c++对象模型》 学习笔记 - 前言
- 《深度探索c++对象模型》学习笔记 - 2 构造函数语义学