2011-05-05 40 views
13

據我所知,不可能調用基類的構造函數。我知道的唯一方法是這樣的:在C++中的一些其他指令後調用基類的構造函數

MyClass::MyClass(/* args */) : Base(/* args */) 
{ 
    // ... 
} 

但這會在開始時調用構造函數。 有什麼辦法可以在構造函數中的其他地方調用它嗎?事情是這樣的:

MyClass::MyClass(/* args */) 
{ 
    // ... instructions 
    Base::Base(/* args */); 
    // ... other_instructions 
} 

根據這一What are the rules for calling the superclass constructor?問題,據我所知,沒有辦法,但我讀here,我猜這是可能的,但如果我嘗試,我得到:

error: invalid use of 'class Base'. 

我做有問題?是否有可能以某種方式做到這一點,或者有沒有其他可能的解決方案來滿足這種需求?

謝謝!

編輯:我明白我忘了一個關鍵點:基類是框架的一部分,因此如果可能的話,不用修改它就可以。

+1

問題是:*你爲什麼需要這個?* – 2011-05-05 08:49:42

+0

答案是 - 不。 – 2011-05-05 08:53:17

+0

由於某種原因,我不能重申這個問題,添加OOP作爲標籤應該是approppriate我認爲。 – amit 2011-05-05 08:59:16

回答

12

如果基類的構造函數需要至少一個參數,你可以使用一個輔助功能,這樣,您可以使用copy-ctor複製默認的初始化基類實例:

Base DoStuffBeforeCtorAndReturnDefaultBase(int arg, Foo foo) 
{ 
    DoStuff(arg, foo); 
    return Base(); 
} 

MyClass::MyClass(int arg, Foo foo) 
    : Base(DoStuffBeforeCtorAndReturnDefaultBase(arg, foo)) 
{ 
    // ... 
} 

或如果Base不必是第一個基類,你可以從一個輔助類派生MyClass

MyClass::MyClass(/* ... */) 
    : DoStuffHelperClass(/* ... */), 
    Base(/* ... */) 
{ 
    // ... 
} 

上述所有要求的「東西」你不依賴這是關於對象初始化(即這些函數不能安全地作爲成員函數,並且不能安全地將this作爲參數傳遞給它們)。

這意味着你可以做一些日誌記錄或類似的事情,但是之後你也可以在基類初始化後做到這一點。

編輯除與DoStuffHelperClass解決方案,當然你可以有成員DoStuffHelperClass,訪問它們,什麼不可以)


雖然我不得不說,我不能使用記得曾經/需要/想要這樣的事情。對於你想要做的事情,很可能有另一種(更可取的)解決方案。

+0

我不知道這些解決方案是否會在我所要做的事情中發揮作用,但無論如何,在我看來,這些解決方案都是我的問題的絕佳答案!謝謝! – 2011-05-07 08:34:18

0

不,因爲它不會安全。
考慮你有:一類A和一個變量A.var
現在考慮B繼承自A,並且在A被初始化之前使用var。你會得到一個運行時錯誤!語言要防止這種情況,所以超類的構造函數必須先初始化。

7

基類在構建自己的類之前總是完全構建。如果您需要對基類的狀態進行更改,則必須在構建之後明確地執行此操作。

例如:如果您想爲默認初始化基類

int DoStuffBeforeCtorAndForwardInt(int arg, Foo foo) 
{ 
    DoStuff(arg, foo); 
    return arg; 
} 

MyClass::MyClass(int arg, Foo foo) 
    : Base(DoStuffBeforeCtorAndForwardInt(arg, foo)) 
{ 
    // ... 
} 

MyClass::MyClass() 
{ 
    // Implicit call to Base::Base() 

    int result = computeSomething(); 
    Base::setResult(result); 

    // ... 
} 
0

不,你不能這樣做,正如其他人在他們以前的答案中所描述的那樣。

你唯一的機會是組成,督察該MyClass使用Base類作爲成員字段:

class MyClass { 
public: 
    /** the methods... */ 

private: 
    Base* _base; 
}; 

以便以後可以初始化_base,當你有需要的信息。無論如何,我不知道這是否適用於您的場景。

+0

不幸的是我認爲我唯一的可能性是創建一個實際的子類。被調用的方法傳遞了我創建的實例作爲參數,並且在那裏我需要我的子類。 – 2011-05-06 21:54:07

2

除了已經編寫的解決方案之外,您還可以使用靜態構造函數並使MyClass的構造函數爲private。

class QtBase{ 
    // ... 
}; 

class MyClass : public QtBase{ 
public: 
    // copy ctor public 
    MyClass(MyClass const& other); 

    static MyClass Create(/*args*/){ 
    // do what needs to be done 
    int idata; 
    float fdata; 
    // work with idata and fdata as if they were members of MyClass 
    return MyClass(idata,fdata); // finally make them members 
    } 

    static MyClass* New(/*args*/){ 
    int idata; 
    float fdata; 
    // work with idata and fdata as if they were members of MyClass 
    return new MyClass(idata,fdata); // finally make them members 
    } 

private: 
    // ctor private 
    MyClass(int a_idata, float a_fdata) 
    : idata(a_idata) 
    , fdata(a_fdata) 
    {} 

    int idata; 
    float fdata; 
}; 

現在,你需要創建的MyClass情況下,無論是作爲:

MyClass obj = MyClass::Create(/*args*/); 

MyClass* ptr = MyClass::New(/*args*/); 
+0

順便說一句:這就是所謂的「命名構造函數」;) – 2011-05-05 13:30:26

+0

如果我正確理解這將是一個解決方案,如果我不需要初始化我的子類的成員。我不能用這個解決方案做到這一點,對吧?謝謝! – 2011-05-05 22:07:03

+0

@Luca:嗯,你總是可以有一個構造函數,讓他的成員已經初始化。:) – Xeo 2011-05-05 22:09:58

7

使用base-from-member idiom「真正」基地的構造函數之前運行代碼類(它是基地):

struct Base { 
    Base(string, int); 
}; 

struct DerivedDetail { 
    DerivedDetail() { 
    value = compute_some_value(); 
    value += more(); 
    value += etc(); 
    other = even_more_code(value); 
    } 
    string value; 
    int other; 
}; 

struct Derived : private DerivedDetail, Base { 
    Derived() : Base(value, other) {} 
    // In particular, note you can still use this->value and just 
    // ignore that it is from a base, yet this->value is still private 
    // within Derived. 
}; 

即使您沒有DerivedDetail中的實際成員,也可以使用。如果你在Base的ctor之前詳細說明你必須做什麼,那麼我可以舉一個更好的例子。

+0

是的!這是我一直在尋找的,謝謝! Upvoted! – 2011-05-07 08:40:01

-1

不是,這是不可能的,因爲構造函數調用的順序是由標準嚴格定義的。基類ctor必須在派生類ctor可以執行之前執行。

相關問題