2013-01-08 34 views
2

我想在父構造函數被調用之前做一些處理。下面的例子說明了爲什麼我想這樣做,儘管爲了清晰起見,我已經做了一些小事。真正的父構造函數正在做一些渲染,但讓我們先試着解決這個問題。如何在一些處理之後調用父構造函數?

本質上,問題出現在由父構造函數調用overriden函數時,但尚未設置子數據。我該如何解決?

class BaseClass { 

public: 
    int myNumber; 

    BaseClass(){ 
     myNumber = 0; 
     this->printNumber(); 
    } 

    virtual void printNumber(){ 
     printf("My number is %d\n", this->myNumber); 
    } 
} 

class ChildClass : BaseClass { 

public: 
    float childNumber; 

    ChildClass(float myNumber) : BaseClass() { 
     this->childNumber = myNumber; 
    } 

    void printNumber(){ 
     printf("My number is %f\n", this->childNumber); 
    } 

} 

回答

2

與其他人一樣上面說的,你不應該叫從構造一個虛擬的成員。但要解決你的問題有一個成語,可以幫助你,它被稱爲基從成員:

http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Base-from-Member

它做什麼,基本上,是利用一個事實,即基類的初始化優勢爲了聲明它們。在基類初始化之前,您可能能夠在單獨的基類中完成您需要做的事情。

class OtherBaseClass { 
    int Num; 
    OtherBaseclass(float num) : Num(num) 
    { 
     printf("My number is %d\n", this->Num); 
    } 
}; 


class ChildClass : OtherBaseClass, BaseClass { 

public: 
    float childNumber; 

    ChildClass(float myNumber) : OtherBaseClass(myNumber), BaseClass() { 
.... 
+2

這裏是這個成語的_Boost_實現:http://www.boost.org/doc/libs/1_52_0/libs/utility/base_from_member.html –

+2

你可以**從構造函數調用一個虛函數。 –

+0

@JonathanWakely真的,我編輯它。 – imreal

9

問題進來時被覆蓋的功能是由父類的構造稱爲,

不,永遠不會發生。在BaseClass的構造函數中,其動態類型也是BaseClass,因此printNumber()調用將解析爲其自己的號碼而不是某些派生類。爲什麼?因爲那時ChildClass的構造函數尚未完成運行,所以尚未創建。

由於@FredLarson評論,下面是關於這個問題的更多信息:http://parashift.com/c++-faq/calling-virtuals-from-ctors.html

+3

這個更多信息:http://www.parashift.com/c++-faq/calling-virtuals-from-ctors.html –

+1

+1感謝您對我的假設指出錯誤。但是,這不是標題中提到的問題的答案,因此我將此標記爲「答案」會感覺不好。 – chacham15

+0

@ chacham15:來自_Nick_的人看起來不錯! –

2

注意,基類的構造函數不能調用派生類的虛函數的版本,也就是你的ChildClass::printNumber()功能不會被調用。

這就是說,如果你想在基類的構造函數之前執行的東西,其中一個辦法是用另一種基類,而其他人之前所說的那樣:

class RunMeFirst 
{ 
    public RunMeFirst() 
    { printf("whatever...\n"); } 
}; 

class ChildClass : private RunMeFirst, public BaseClass 
{ /*...*/ }; 
0

有幾件事情是一個基類之前運行的構造函數:

  • 的參數初始化
  • 虛基類構造
  • 其他基地類聲明早期的構造函數

一種常用的解決方案稱爲「基於成員慣用語」,並涉及將成員移動到首先構造的新基類。

1

您是否必須在基類中實現渲染功能?你可以改爲使用組合而不是繼承。使用組合可以讓您輕鬆控制成員初始化順序,例如:

#include <iostream> 

class renderer 
{ 
public: 

    renderer(int number) 
    { 
     std::cout << "Number is " << number << std::endl; 
    } 
}; 

class foo 
{ 
public: 

    foo() 
     : number_(12) 
     , renderer_(number_) 
    { 
    } 

private: 

    int number_; 
    renderer renderer_; 

}; 

int main() 
{ 
    foo bar; 
} 

一般來說,prefer composition to inheritance。此外,從設計角度來看,Liskov Substitution Principle也可能在這裏使用。

0

感謝@ K-ballo指出錯誤,並且因爲這樣我就能夠重構代碼來做我想做的事情,但是因爲這不是對這個問題的技術正確答案,所以我會離開正確的答案是。

class BaseClass { 

public: 
    int myNumber; 

    BaseClass(bool initialize = true){ 
     myNumber = 0; 
     if (initialize){ 
      this->initialize(); 
     } 
    } 

    void initialize(){ 
     this->printNumber(); 
    } 

    virtual void printNumber(){ 
     printf("My number is %d\n", this->myNumber); 
    } 
} 

class ChildClass : BaseClass { 

public: 
    float childNumber; 

    ChildClass(float myNumber) : BaseClass(false) { 
     this->childNumber = myNumber; 
     this->initialize(); 
    } 

    void printNumber(){ 
     printf("My number is %f\n", this->childNumber); 
    } 

} 
相關問題