重溫《Inside The C++ Object Model》(2) --Default-Constructor的建構操作
來源:程序員人生 發布時間:2015-01-13 08:29:36 閱讀次數:2731次
//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
", bar.next);
cout << "Un initialization" << endl;
}
else
{
cout << "Initialization" << endl;
}
}
“帶有Default Constructor” 的 Member Class Object
(1)如果class A 內含有1個或1個以上的member-class-object, 那末class A 的每個constructor必須調用每一個member-classes的default-constructor; 編譯器會擴大已存在的constructor, 在其中安插1些代碼, 使得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, 就會有1個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;
}
”帶有Default Constructor” 的 Base Class
在派生類中,如果同時存在member-class-object, 則先調用其base-class-constructor, 而后調用member-class-object的constructor.
”帶有1個Virtual Function” 的 Class
以下的兩種情況:
(1)class 聲明(或繼承)1個virtual-function.
(2)class 派生自1個繼承串鏈, 其中有1個或更多的virtual-base-classes.
都會有以下的擴大操作在編譯期產生:
[1]1個 virtual-function-table(在cfront中被稱為vtbl)會被編譯器生成, 內放class的virtual-function地址;
[2]在每個class-object中, 1個額外的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);
”帶有1個Virtual Base Class” 的 Class
假定有以下繼承關系與代碼:

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()可以延遲至履行才決定下來;
該功能則是靠”在派生類對象中的每個虛基類中安插1個指針(_vbcX [virtual-base-class-X])”完成. 所有”經過reference/pointer來存取1個virtual-base-class”的操作都可以通過相干的指針來完成.則foo()函數可以改寫以下:
void foo(const X *px)
{
//__vbcX表示由編譯器產生的指針, 指向virtual-base-class-X
px -> __vbcX -> memFunction();
}
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈