2013-02-03 92 views
1

我有一個基類基地它定義了一個虛函數。類派生的現在繼承它並實現/覆蓋該虛函數。下面的代碼工作得很好:虛擬函數+帶基類指針的STL容器

Base* pB = new Derived(); 
pB->virtual_function(); // function of class Derived gets called -> good 

我的問題是,我現在我所有的衍生實例存儲在STL容器std::map<ID, Base*>。這似乎會導致問題,因爲當我稍後迭代該容器並嘗試每個基地 *調用我的虛函數時,運行時只能將指針識別爲類型基地 *並且不會在類中調用覆蓋的實現派生

有沒有一種方法可以按預期工作,或者我在這裏錯過了一個關鍵點?

編輯1:請求一些額外的代碼,所以在這裏我們去:

std::map<ComponentType, Base*> m_Components; 
// The factory instantiates a Derived* (via functors) and returns it as Base* 
Base* pB = m_pComponentFactory->createComponent(this, type); 
// Lazy insert (since there is no map entry with key 'type' at that stage) 
m_Components[type] = pB; 

[...] 

Base* pB; 
for(ComponentMap::const_iterator it = m_Components.begin(); it != m_Components.end(); ++it) 
{ 
    pB = it->second; 
    pB->virtual_function(); // goes to Base instead of Derived 
} 

編輯2:有一件事我剛剛意識到的是,我不叫dynamic_cast(或類似的東西)後通過仿函數創建Derived實例(但我不知道該怎麼投它,因爲它全是通用的/動態的)。這僅僅是一個return creator(),創造者就是函子。這是問題嗎?

typedef Base*(*ComponentCreator)([some params]); 

編輯3:(自時基開始渲染和位置被派生類) 實際函子例如這樣定義:

創建者類型(functon型)的定義

&Renderable::Create<Renderable> // or 
&Location::Create<Location> 

其中Create()方法是類Base中的模板函數。

template<typename T> 
static Component* Create([some params]) 
{ 
    return new T([some params]); 
} 

編輯4: 的問題似乎是我的clone()+ CopyConstructor處理。我的克隆目前看起來是這樣的:

Base* Base::clone() const 
{ 
    return new Base(*this); 
} 

因爲我只創建一個基地 *,虛擬分辨率以後不能工作。我現在留下的問題是,我錯過了一個想法,如何改變克隆。如所示編輯1我有我的m_Components地圖與基地*指針。我現在需要克隆他們,但我只知道他們是基地 *而不是確切的衍生物。想到的一個想法可能是存儲用於創建派生的實例的仿函數,以便稍後重用它。所以我的克隆看起來像這樣:

Base* Component::clone() const 
{ 
    return m_pCreationFunctor([some params]); 
} 

有人看到更好的方法?

+0

你能告訴你如何存儲你的元素在容器中?理論上,你不應該有這個問題。 –

+2

你做錯了什麼。這個想法是正確的,應該工作。你是否意外地在任何地方切片? –

+0

當你將它們存儲在你的容器中時,你必須以某種方式存儲一個指向基類的指針,而不是派生類 – Lieuwe

回答

5

你是切片的受害者。當你複製一個Base時,你將失去該對象的Derived部分。有關更多詳細信息,請參閱http://en.wikipedia.org/wiki/Object_slicing。如果基類不應該被實例化,你可能會考慮將其抽象化以防止將來發生這種錯誤。

在這種情況下的修復可能是有一個虛擬的Base * clone()方法並在派生類中覆蓋它。

class Base{ 
... 
virtual Base * clone() const = 0; 
... 
}; 

class Derived : public Base { 
... 
Base * clone() const override { return new Derived(*this); } 
... 
}; 

如果你真的想避免重寫clone方法,你可以使用一箇中間CRTP類即

struct Base{ 
    virtual Base * clone() = 0; 
}; 

template <typename D> 
struct B : public Base { 
    virtual Base * clone() { return new D(*static_cast<D*>(this)); } 
}; 

struct D : public B<D>{}; 
+0

+1 CRTP類 –

+0

不妨利用協變返回類型以及:) – Ylisar

+0

葉 - 認爲最好保持簡單! – jmetcalfe