2012-12-20 123 views
2

當你有一個類型依賴於某些約束的成員時,你如何設計多態。多態設計,抽象類模板

說我有這樣的:

template<typename T> 
class Base 
{ 
public: 
    Base() = default; 
    virtual ~Base() = default; 
    T member; 
}; 

class DerivedA : public Base<int> 
{ 
public: 
    DerivedA() {member = 5;} 
}; 

class DerivedB : public Base<float> 
{ 
public: 
    DerivedB() = default; 
}; 

我希望能夠建立根據不同的參數,一個新的派生類對象,即:

Base *b; 
if (something) 
    b = new DerivedA(); 
else 
    b = new DerivedB(); 

很顯然,我不能這樣做,因爲我需要爲b的聲明提供模板參數。

這是不好的設計?你如何處理這個問題?

我可以寫一個小包裝:

class Wrapper() {}; 

template<typename T> 
class Base : public Wrapper 
{ 
// ... 
}; 

Wrapper a, b; 
a = new DerivedA; 
b = new DerivedB; 

但以後我不會再有機會直接向memberBaseDerived聲明其他方法。我需要演員:reinterpret_cast<DerivedA*>(a)->member,使多態無用。

謝謝

+0

在你的設計中有一個問題...包裝界面應該沒問題,但你必須扭轉問題才能工作。 – Synxis

+0

這讓我想起http://en.wikipedia.org/wiki/Policy-based_design – user1849534

+0

第三級基地? –

回答

0

包裝設計應該是你正在尋找的。問題是C++是靜態類型的,所以你不能聲明成員而不指定它的類型。避免這種情況的常見方法是設計一個支持所需功能的基類,並在派生類中實現特定的行爲,就像您一樣。

可能問題是您的課程不支持您需要的所有功能。儘量避免直接使用成員,並將其用法包裝到虛擬方法中。在派生類中重新實現這些方法。

如果這仍然不是一個選項,請考慮提取您的成員的方法。也許虛擬getter和setter具有適當的轉換。

作爲最後的手段,考慮boost :: variant,boost :: any。但實際上他們是使用類似於包裝的技術來實現的。所以你得到包裝的包裝。

0

那麼,如果「訪問」依賴於模板參數T(例如閱讀Base.member),那麼你必須爲它供給莫名其妙。投射到其中一個派生類是實現它的一種方法,但您不需要reinterpret_cast。您需要正確地開始使用指針/引用,以避免停產,並讓可替代性工作:

Wrapper *a, *b; 
a = new DerivedA; 
b = new DerivedB; 

int a_member = static_cast<DerivedA*>(a)->member; 
float b_member = static_cast<DerivedB*>(b)->member; 

如果你添加一個虛擬方法Wrapper,使其多態,你可以做動態轉換以及:

DerivedB* b_derived = dynamic_cast<DerivedB*>(b); 
if (b_derived != nullptr) { 
    float b_member = b_derived->member; 
    // ... 
}