1. 程式人生 > >建構函式語義學---default constructor

建構函式語義學---default constructor

C++ Annatated Reference Manual告訴我們:“default construct會在需要的時候被編譯器產生出來”。關鍵字眼在於什麼時候需要以及被誰需要。一般說來,default construct的需求方有程式設計師和編譯器。如果程式設計師需要,那麼他就有責任在程式中宣告construct function。如果是編譯器需要,那麼編譯器就會在程式中合成construct。當然,合成construct只會執行編譯器需要的行動。下面講一下編譯器合成的default construct有效的四種情況:

1)帶有“default constructor”的menber class object

如果一個類沒有任何construct,但它含有一個member object,而後者有default construct,那麼這個class的implict default construct就是“nontrival”,編譯器需要為此合成一個default constructor.不過這個合成操作只有在constructor真正呼叫時才會發生。

一個有趣的問題就發生了,編譯器如何避免在不同的編譯模組中合成出多個default constructor?就解決方法就是把合成的default construct ,destructor,assigment copy operator都已inline的方式完成。一個inline函式都有靜態連結,不會被檔案以外的部分看到。

舉個例子,在下面的程式中,編譯器為class Bar合成一個default constructor:

class Foo{

      public;

                Foo();

                 Foo(int );

}

class Bar{

    public:

          Foo foo;

    char *str;

}

void foo_bar(){

        Bar bar;//必須再次初始化

       if(str){

}

}

被合成的Bar default constructor 內含有必要的程式碼,能夠呼叫Foo default constructor來處理membert object Bar::foo,但它並不產生任何程式碼來初始化Bar::str。將Bar::str初始化是程式設計師的責任,將Bar::foo初始化時編譯器的責任。被合成的default constructor看起來像這樣:

inline Bar::Bar(){

        foo.Foo::Foo();

}

再一次注意,被合成的default construct是編譯器的需要,而不是程式設計師的需要。為了能讓這個程式片段真正執行起來,字串str也需要被初始化。假設程式設計師經由下面的default constructor提供str的初始化操作:

Bar::Bar(){

     str=0;

}

現在程式的需求滿足了,但是編譯器還需要初始化member object foo,由於default constructor已經被明確定義出來了,編譯器沒辦法合成第二個。編譯器採取的行動是將初始化foo的程式碼插入到Bar default constructor中,使得使用者程式碼在執行之前先呼叫必要的default constructor,擴大後的程式碼可能是:

Bar::Bar(){

       foo.Foo::Foo();//附加的編譯器程式碼

       str=0;//explict user code

}

如果有多個class member object 都要求construct初始化操作,編譯器將如何做呢?c++語言要求以“ member object”在class中的宣告次序來呼叫各個construct,這一點由編譯器來完成。它會為每一個member object安插程式程式碼,以“member宣告次序”呼叫每一個member object的default constructor,這些程式碼將會被安插在explict user code之前。舉個例子

class Dopey{

public:

Dopey();

}

class Sneezy{

public:

Sneezy();

Sneezy(int );

}

class Snow_white{

        public:

    Dopey dopey;

    Sneezy sneezy;

private;

int number;

}

如果class Snow_white沒有定義default constructor,編譯器就會合成一個nontrival constructor被合成出來。然而,Snow_white定義了下面的default constructor。

Snow_white::Snow_white();sneezy(1023){

     number=2045;

}

它會被擴張如下:

Snow_white::Snow_white();sneezy(1023){

     //插入member class object

   dopey.Dopey::Dopey();

   sneezy.Sneezy::Sneezy(1024);

//explict user code

number=2045;

}

2)帶有default constructor的Base Class

如果一個沒有任何constructor的class派生自一個帶有“default constructor”的base class,那麼derive class的default constructor會被是為nontrivial,並因此需要被合成出來。他將呼叫上一層base class的default constructor(按照他們的宣告次序),對一個後繼派生的class而言,這個合成的construtor和一個被明確提供的default constructor沒有什麼差異。

如果設計者提供多個constructor,但其中都沒有Base Class的default constructor呢?編譯器會擴張現有每一個constructor,將所有用以呼叫必要的dafault constructor的程式碼加進去,它不會合成一個新的default constructor,這是因為其它由“user 所提供的constructor存在的緣故”,如果同時存在“帶有default constructor”的membe class object,那些default constructor也會被呼叫----在所有base class constructor都被呼叫之後。