2009-09-21 89 views
4

我有,我想看看這樣一個基類:如何獲得C++構造函數中的多態行爲?

class B 
{ 
    // should look like: int I() { return someConst; } 
    virtual int I() = 0; 
    public B() { something(I()); } 
} 

被強制派生類重寫I並迫使其點的每個對象被創建時被調用。這被用來做一些簿記,我需要知道什麼類型的對象正在構建(但我否則將當前對象作爲基類)。

這不起作用,因爲C++不會讓你從構造函數中調用一個抽象的虛函數。

有沒有辦法獲得相同的效果?


基於this link它似乎是答案是沒有辦法得到我想要的東西。然而它說的是:

簡短的回答是:沒有。基類不知道它是從哪個類派生出來的,這也是一件好事。 [...]也就是說,直到構造函數Derived1 :: Derived1開始,對象纔會正式成爲Derived1的實例。

但是在我的情況,我不想知道它,但它會成爲。事實上,只要用戶可以(事後)將其映射到一個班級,我甚至不關心我回來的東西。所以我甚至可以使用類似返回指針的東西並且避開它。

(現在回讀該鏈接)

+0

閱讀此:http://stackoverflow.com/questions/1425695/1426834。 您可以使用PIMPL。 – 2009-09-21 10:54:17

回答

6

不能調用虛方法從構造函數(或者更精確地說,你可以打電話他們,但你最終會調用成員函數從目前正在構建的類中),問題是派生對象在那個時刻還不存在。關於它幾乎沒有什麼可做的,從構造函數多態調用虛擬方法根本就不成問題。例如,您應該重新考慮您的設計 - 將常量作爲參數傳遞給構造函數。

class B 
{ 
public: 
    explicit B(int i) 
    { 
     something(i); 
    } 
}; 

查看C++ faq瞭解更多信息。如果你真的想在施工期間打電話虛擬功能,read this

+0

你的意思是「你不能......」? – Naveen 2009-09-21 06:53:19

+0

是的,這是一個錯字,謝謝你Naveen :) – avakar 2009-09-21 06:54:34

+0

在構造函數是一個解決方法之後調用一個init()方法。但是,隨後你需要在班級建造的任何地方進行改變 - 如果你使用的是工廠,這很好。 – 2009-09-21 06:59:35

0

也許在每個派生類型上使用靜態工廠方法?這是在.NET中構造奇特對象的常用方法(請閱讀:具有非常具體的初始化要求的對象),我已經開始意識到這一點。

class Base 
{ 
    protected Base(int i) 
    { 
    // do stuff with i 
    } 
} 

class Derived : public Base 
{ 
    private Derived(int i) 
    : Base(i) 
    { 
    } 

    public Derived Create() 
    { 
    return new Derived(someConstantForThisDerivedType); 
    } 
} 

在調用構造函數的基礎虛擬方法一般是令人難以接受的,因爲你永遠是某些特定方法的行爲,以及(如別人已經指出的那樣)衍生構造將還未被調用。

0

這不會作爲派生類的工作時,執行基類的構造並不存在:

class Base 
{ 
public: 
    Base() 
    { 
     // Will call Base::I and not Derived::I because 
     // Derived does not yet exist. 
     something(I()); 
    } 

    virtual ~Base() = 0 
    { 
    } 

    virtual int I() const = 0; 
}; 

class Derived : public Base 
{ 
public: 
    Derived() 
    : Base() 
    { 
    } 

    virtual ~Derived() 
    { 
    } 

    virtual int I() const 
    { 
     return 42; 
    } 
}; 

相反,你可以在參數添加到基類的構造函數:

class Base 
{ 
public: 
    explicit Base(int i) 
    { 
     something(i); 
    } 

    virtual ~Base() = 0 
    { 
    } 
}; 

class Derived : public Base 
{ 
public: 
    Derived() 
    : Base(42) 
    { 
    } 

    virtual ~Derived() 
    { 
    } 
}; 

或者如果你真的喜歡OOP,你還可以創建幾個附加類:

class Base 
{ 
public: 
    class BaseConstructorArgs 
    { 
    public: 
     virtual ~BaseConstructorArgs() = 0 
     { 
     } 

     virtual int I() const = 0; 
    }; 

    explicit Base(const BaseConstructorArgs& args) 
    { 
     something(args.I()); 
    } 

    virtual ~Base() = 0 
    { 
    } 
}; 

class Derived : public Base 
{ 
public: 
    class DerivedConstructorArgs : public BaseConstructorArgs 
    { 
    public: 
     virtual ~DerivedConstructorArgs() 
     { 
     } 

     virtual int I() const 
     { 
      return 42; 
     } 
    }; 

    Derived() 
    : Base(DerivedConstructorArgs()) 
    { 
    } 

    virtual ~Derived() 
    { 
    } 
};