标签:c++ 面向对象 constructor 对象模型 指针
//constructor/non-constructor的区别 class Foo { public: //Foo():val(0),next(NULL) {} int val; Foo *next; }; void foo_bar() { Foo bar; if ( bar.val && bar.next ) { cout << bar.val << endl; printf("%p\n", bar.next); cout << "Un initialization" << endl; } else { cout << "Initialization" << endl; } }
(1)如果class A 内含有一个或一个以上的member-class-object, 那么class A 的每一个constructor必须调用每个member-classes的default-constructor; 编译器会扩张已存在的constructor, 在其中安插一些代码, 使得user-code在被执行前, 先调用必要的default-constructors.
(2)C++语言要求以”member-objects 在 class 中的生命次序”来调用各个constructors.
假设有以下类:
class Dopey { public: Dopey(); // ... etc ... }; class Sneezy { public: Sneezy(int); Sneezy(); // ... etc ... }; class Bashful { public: Bashful(); // ... etc ... }; class Snow_White { public: Dopey dopey; Sneezy sneezy; Bashful bashful; // ... etc ... private: int mumble; };
如果Snow_White没有定义default-constructor, 就会有一个non-trivial-constructor被合成出来, 依序调用Dopey, Sneezy, Bashful的default-constructors. 然而如果Snow_White定义了下面这样的default-constructor:
Snow_White::Snow_White() : sneezy(1024) { mumble = 2048; }
它会扩张为:
//编译器扩张后的default constructor //C++伪码 Snow_White::Snow_White() : sneezy(1024) { //插入 member class object //调用其 constructor dopey.Dopey::Dopey(); sneezy.Sneezy::Sneezy(); bashful.Bashful::Bashful(); //explicit user-code mumble = 2048; }
在派生类中,如果同时存在member-class-object, 则先调用其base-class-constructor, 而后调用member-class-object的constructor.
以下的两种情况:
(1)class 声明(或继承)一个virtual-function.
(2)class 派生自一个继承串链, 其中有一个或更多的virtual-base-classes.
都会有如下的扩张操作在编译期产生:
[1]一个 virtual-function-table(在cfront中被称为vtbl)会被编译器生成, 内放class的virtual-function地址;
[2]在每一个class-object中, 一个额外的pointer-member(也就是vptr)会被编译器合成出来, 内含相关的class-virtual-function-table(class-vtbl)的地址.
则假设有如下继承关系和代码:
void flip(const Widget &widget) { widget.flep(); }
则widget.flip()的虚拟引发操作会被重新改写, 以使用widget的 vptr 和 vtbl中的flip()条目:
//widget.flip() 中的虚拟引发操作的改变 (*widget.vptr[1]).(&widget);
假设有如下继承关系与代码:
class X { public: virtual void memFunction() const { cout << "In X" << endl; } }; class A : public virtual X { public: void memFunction() const { cout << "In A" << endl; } }; class B : public virtual X { public: void memFunction() const { cout << "In B" << endl; } }; class C : public A, public B { public: void memFunction() const { cout << "In C" << endl; } }; void foo(const X *px) { px -> memFunction(); } int main() { foo(new X); foo(new A); foo(new B); foo(new C); } /* void foo(const X &rx) { rx.memFunction(); } int main() { foo(X()); foo(A()); foo(B()); foo(C()); } */
编译器无法固定住foo()之中”经由px而存取的X::memFunction()”的实际偏移位置, 因为px的真正类型可以改变, 编译器必须改变”执行存取操作”的那些代码, 使得X::memFunction()可以延迟至执行才决定下来;
该功能则是靠”在派生类对象中的每一个虚基类中安插一个指针(_vbcX [virtual-base-class-X])”完成. 所有”经由reference/pointer来存取一个virtual-base-class”的操作都可以通过相关的指针来完成.则foo()函数可以改写如下:
void foo(const X *px) { //__vbcX表示由编译器产生的指针, 指向virtual-base-class-X px -> __vbcX -> memFunction(); }
重温《Inside The C++ Object Model》(2) --Default-Constructor的建构操作
标签:c++ 面向对象 constructor 对象模型 指针
原文地址:http://blog.csdn.net/zjf280441589/article/details/42360345