2014-01-14 85 views
4

注意:不是C++ 11 Delegated Constructor Pure Virtual Method & Function Calls -- Dangers?的重複。這個其他問題是指一個概念上類似的問題,並不真正爲這種情況提供解決方案。C++ 11構造函數的繼承和純虛方法

考慮下面的程序:

#include <iostream> 
using std::cout; 
using std::endl; 

class Base { 
    virtual void init() = 0; // a hook function 
    public: 
    Base(int a, int b) { /* ... */ init(); } 
    Base(char a, int b) { /* ... */ init(); } 
    Base(char a, int b, double* c) { /* ... */ init(); } 
    /* etc. Dozens of constructors */ 
};  

class Derived1 : public Base {  
    void init() { cout << "In Derived1::init()" << endl; }  
    public:  
    using Base::Base;  
};  

class Derived2 : public Base {  
    void init() { cout << "In Derived2::init()" << endl; }  
    public:  
    using Base::Base;  
};  

int main() { 
    Derived1 d1(1, 2); 
    Derived2 d2('a', 3); 
    return 0; 
} 

此代碼顯然不能運行(儘管它帶有警告編譯一些編譯器)。問題是,實現這種模式的最好方法是什麼?假設Base中有幾十個派生類和幾十個構造函數,重新實現派生類中的Base構造函數(在派生構造函數的主體中調用基礎構造函數和init())並不是很理想。

+1

我建議刪除許多換行符和空的註釋,以便更容易理解在類似的小瀏覽器窗口中找到完整的代碼。 – dornhege

回答

2

該代碼需要在派生類構造函數中進行,直到對象具有派生類型才能運行該代碼。

但是你可以一次用完美轉發其添加到所有構造函數:

class Derived1 : public Base 
{ 
public: 
    template<typename... T> 
    explicit Derived1(T&&... t) : Base(std::forward<T>(t)...) { 
     std::cout << "Derived1::init logic goes here" << endl; 
    } 
}; 
+0

@DavidHollman:是的,沒有。模板構造函數永遠不會是複製或移動構造函數,因此按值傳遞不會使用該模板。但是當你直接調用一個構造函數時,你可能會得到不想要的結果。見http://akrzemi1.wordpress.com/2013/10/10/too-perfect-forwarding/ –

+0

(重新發布,以便您的評論將有意義)這不會重載默認的副本和移動構造函數? –

0

使這些類的,這個對象創建後調用init()專業廠家

1

另一種方法是「命名'構造函數:

#include <iostream> 

class Base 
{ 
    public: 
    template <typename Derived> 
    static Derived construct() { 
     Derived derived; 
     derived.hello(); 
     return derived; 
    } 

    protected: 
    Base() {}; 

    public: 
    virtual ~Base() {}; 

    public: 
    virtual void hello() = 0; 
}; 

class Derived : public Base 
{ 
    public: 
    virtual void hello() { 
     std::cout << "Hello\n"; 
    } 
}; 

int main() 
{ 
    Derived d = Base::construct<Derived>(); 
}