2013-10-31 154 views
0

以下是我正在嘗試完成的操作:C++ 11非模板化基類中的純虛擬'模板化'返回類型

我試圖創建各種類型的鏈接列表。爲了做到這一點,我認爲多態是一個很好的方法。

我有兩個類,AttributeBase和Attribute。 AttributeSet使用AttributeBase,它只存儲屬性<T>(作爲AttributeBase *)的鏈接列表的開始和結束點,並對列表進行修改。 AttributeBase是屬性<T>的基類,僅在設計中用於製作泛型指針。屬性<T>當然是存儲實際值的特定類型的AttributeBase。每個屬性<牛逼>的主要數據是一種遺傳性的字符串(屬性的名稱,或者「關鍵」如果你願意)和類型T的值

所以,我迄今(簡體):

class AttributeBase 
{ 
    public: 
    AttributeBase() = delete; 
    AttributeBase* GetNext() { return next; }; 
    AttributeBase* GetPrev() { return prev; }; 
    std::string GetName() { return name; }; 
    //Sometimes I need to get/set the value stored in a derived class 
    //But, how would I define the function here since the return 
    //type is of type T as defined in Attribute? 
    virtual ???? GetValue = 0; 
    virtual void SetValue(????) = 0; 

    friend class AttributeSet; 
    private: 
    AttributeBase* next = nullptr; 
    AttributeBase* prev = nullptr; 
    std::string name; 
}; 

template <class T> 
class Attribute : public AttributeBase 
{ 
    public: 
    Attribute(std::string _name, T _value){ name = _name; value = _value }; 
    T GetValue(){ return value; }; 
    void Setvalue(T){ value = T; }; 
    private: 
    T value; 
}; 

class AttributeSet 
{ 
    public: 
    template <class T> 
    void Add(std::string,T); //Add an Attribute<T>(std::string,T) to the list 
    void Delete(std::string); 
    bool Contains(std::string _name); //Scan the list to determine if an 
             //attribute with name of _name exists 
    template <class T> 
    T Get(std::string); //Scan the list for 'name' and return 
         //AttributeBase*->GetValue() 
    private: 
    AttributeBase* start = nullptr; 
    AttributeBase* end = nullptr; 
} 

因爲我試圖保持AttributeBase的泛型和非模板化(以避免在AttributeSet中強類型的開始和結束指針),這就產生了一個問題。如何爲虛函數BaseAttribute :: GetValue()指定一個尚未指定的返回類型。我第一次嘗試使用auto,得到了一個編譯錯誤。

由於沒有實際的AttributeBase實例被創建(並且默認構造函數被刪除),我認爲可以省略GetValue並在派生類中定義它。但是,如果我嘗試* AttributeBase-> GetValue()它錯誤了,因爲GetValue()沒有在AttributeBase中定義,只有子類。你會認爲編譯器會知道指針必須指向派生類(唯一的派生類型),因爲不能直接構造AttributeBase。

因此,爲了使用GetValue(),我必須提前知道前一個值的類型,才能將AttributeBase *轉換爲Attribute *。如果AttributeBase本身是模板化的,並且包含一個值T型,這將是微不足道的。然後我可以訪問AttributeBase * - > type來確定我需要投射的指針的類型。然而,正如我所說的,模板AttributeBase破壞了對象的預期用途。

更可能的是,我以完全錯誤的方式(再一次)討論這個問題。但是在這一點上,我堅持想法。任何幫助,將不勝感激!

+0

您可以舉一個使用'AttributeBase :: GetValue'或'AttributeBase :: SetValue'的代碼示例嗎? – aschepler

回答

1

因此,一個真正的通用解決方案不存在。你不能從基類中獲取任意類型,因爲你的基類虛函數的所有覆蓋必須具有相同的返回類型。

這給你留下了兩個選擇。

首先,您可以預先決定讓您的列表中包含從某些常見基類型派生的任何對象。這會嚴重限制你可以放入列表中的東西,但至少你有這些對象的完全自由。

其次,根據您希望在對象進入列表後實際執行的操作,可以查看新的Boost.TypeErasure庫。如果你需要處理所有的事情,比如輸出全部或者少量的操作,這可以幫助你達到目標。

+0

我會指出,如果類型是協變的,你可以覆蓋不同的返回類型。雖然這在這個特定情況下並不適用。 –

+0

我已經爲我的服務器代碼使用了Boost :: Asio(所以簡單得多!),所以我猜想另一個Boost不會太多傷害。我會看看它,並希望儘快報告。我應該注意到我是Boost的新手,所以這可能需要一點時間;) –

+0

@FrançoisMoisan你說得對,在這種情況下,我打算將標準類型存儲在我的列表中。 –

0

由於GetValueSetValue的簽名取決於類型,因此它們需要是模板。但是他們可以是模板成員而不需要類模板。

class AttributeBase 
{ 
    public: 
    template <typename T> T GetValue() const; 
    template <typename T> void SetValue(T); 
//... 
}; 

template <typename T> 
T AttributeBase::GetValue() const 
{ 
    return dynamic_cast<Attribute<T>&>(*this).GetValue(); 
} 

template <typename T> 
void AttributeBase::SetValue(T val) 
{ 
    dynamic_cast<Attribute<T>&>(*this).SetValue(val); 
} 

template <typename T> 
T AttributeSet::Get(std::string const& name) const 
{ 
    // (assuming a private helper method Find().) 
    const AttributeBase* attr = Find(name); 
    if (!attr) 
     throw std::invalid_argument("attribute not in set"); 
    return attr->GetValue<T>(); 
} 

儘管如此:如果碰巧使用了錯誤的類型,這些函數都會拋出異常。並且SetValue可能會自動推斷其模板參數,並可能不正確。例如,如果aAttributeBase&參考,其確實是Attribute<long int>,則a.SetValue(1)a.SetValue<int>(1)相同,這將拋出。正確的表達式是a.SetValue<long int>(1)(或a.SetValue(1L),但我更喜歡顯式模板參數)。

+0

這很棒,我沒想過。如果他們是模板化的,他們不一定需要是虛擬的......但是,如果我這樣做了,那麼我就不能像AttributeSet.Set(「thename」,25)那樣做,而不做某事比如在AttributeBase中存儲一個代表所用類型的值。然後,每當我想要設置一個模糊的(int,long,short等)值時,我都必須打開它。我剛剛用下面推薦的Boost完成了它(這就是爲什麼我要把它標記爲最好),但我也會嘗試你的方式,看看它是如何去的= D –

+0

我設法把它拉下來= D有一點需要注意,因爲我使用了指針(畢竟這是一個鏈表),所以我必須將dynamic_cast更改爲static_cast。我得到的錯誤:錯誤:不能dynamic_cast'this'(類'class AttributeBase * const')鍵入'類屬性 \ * const'(源類型不是多態),也不能dynamic_cast'\ *(AttributeBase (類型'AttributeBase')類型'類屬性&'(源類型不是多態) –

+0

要修復「源類型不是多態」錯誤,您只需要使析構函數'AttributeBase'虛擬(無論如何這可能是一個好主意)。 – aschepler