2013-05-13 91 views
29

我需要在單個向量中存儲多種類型的模板類。C++一個包含多種類型的模板類的std :: vector

例如,爲:

template <typename T> 
class templateClass{ 
    bool someFunction(); 
}; 

我需要將存儲所有的一個載體:

templateClass<int> t1; 
templateClass<char> t2; 
templateClass<std::string> t3; 
etc 

據我知道這是不可能的,如果是會有人說怎麼樣?

如果無法解釋如何做出如下工作?

作爲解決辦法,我嘗試使用基本非模板類,並從中繼承模板類。

class templateInterface{ 
    virtual bool someFunction() = 0; 
}; 

template <typename T> 
class templateClass : public templateInterface{ 
    bool someFunction(); 
}; 

我然後創建了一個矢量來存儲基地「templateInterface」級:

std::vector<templateInterface> v; 
templateClass<int> t; 
v.push_back(t); 

這將產生以下錯誤:

error: cannot allocate an object of abstract type 'templateInterface' 
note: because the following virtual functions are pure within 'templateInterface' 
note: virtual bool templateInterface::someFunction() 

爲了解決這個錯誤我在取得的功能templateInterface不是通過提供一個函數體來進行純虛擬,而是在編譯時調用該函數而不是使用overide而是在虛函數中使用body。

如:

class templateInterface{ 
    virtual bool someFunction() {return true;} 
}; 

template <typename T> 
class templateClass : public templateInterface{ 
    bool someFunction() {return false;} 
}; 

std::vector<templateInterface> v; 
templateClass<int> i; 
v.push_back(i); 
v[0].someFunction(); //This returns true, and does not use the code in the 'templateClass' function body 

有什麼辦法來解決這個問題,這樣的重寫功能被使用,或者是有其他的解決方法來存儲多種模板類型中的一個載體?

+0

看看這個鏈接http:// stackoverflow。com/questions/5627215/how-to-make-a-vector-of-template-structs – Elior 2013-05-13 17:25:11

回答

24

爲什麼您的代碼不起作用:

調用虛函數不使用多態。它調用爲編譯器所看到的確切符號類型定義的函數,而不是運行時類型。當你將子類型插入到基類型的向量中時,你的值將被轉換成爲基類型(「類型切片」),這不是你想要的。對它們調用函數現在將調用爲基類型定義的函數,因爲不是是該類型的

如何解決這個問題?

同樣的問題可以與此代碼段被再現:

templateInterface x = templateClass<int>(); // Type slicing takes place! 
x.someFunction(); // -> templateInterface::someFunction() is called! 

多態性僅適用於一個指針參考類型。然後它將使用指針/引用背後的對象的運行時類型來決定調用哪個實現(通過使用它的vtable)。

轉換指針對於類型切片是完全「安全的」。您的實際的值根本不會被轉換,多態性將按預期工作。

實施例,類似於上面的代碼段:

templateInterface *x = new templateClass<int>(); // No type slicing takes place 
x->someFunction(); // -> templateClass<int>::someFunction() is called! 

delete x; // Don't forget to destroy your objects. 

什麼矢量?

所以你必須在你的代碼中採用這些改變。您只需將指針存儲到向量中的實際類型,而不是直接存儲值。

使用指針時,你也必須關心刪除你分配的對象。爲此,您可以使用智能指針,該指針自動關心刪除。 unique_ptr就是這樣一種智能指針類型。只要它超出範圍(「唯一所有權」 - 作爲所有者的範圍),就會刪除指針。假設你的對象的生命週期是綁定到這個範圍,你應該使用什麼:

std::vector<std::unique_ptr<templateInterface>> v; 

templateClass<int> *i = new templateClass<int>(); // create new object 
v.push_back(std::unique_ptr<templateInterface>(i)); // put it in the vector 

v.emplace_back(new templateClass<int>()); // "direct" alternative 

然後,調用虛函數的語法如下這些元素之一:

v[0]->someFunction(); 

確保您將使所有功能虛擬應該可能被子類覆蓋。否則,他們的重寫版本將不會被調用。但既然你已經引入了一個「接口」,我相信你正在使用抽象函數。

替代方法:

其它方法來完成你想要的是在矢量使用變種類型。有一些變體類型的實現,Boost.Variant是非常流行的。如果您沒有類型層次結構(例如,當您存儲基元類型時),此方法尤其好。然後你會使用一個向量類型,如std::vector<boost::variant<int, char, bool>>

+0

智能指針_may_是正確的解決方案,但在他的示例代碼中,他沒有動態分配對象。如果它們是具有靜態生命週期的對象,則不需要在它們上使用智能指針,只需要獲取它們的地址。如果他確實需要一份副本(因爲初始化對象的壽命不足),那麼你可能應該這樣說。 – 2013-05-13 17:31:13

+0

'v.emplace_back(new templateClass ();' – 2013-05-13 17:31:18

+0

@JamesKanze:在他的原始代碼中,載體包含了當地人的副本,除非他另有說明,否則我猜測載體需要保留副本,需要對多態性進行動態分配 – 2013-05-13 17:32:23

2

多態只能通過指針或引用。你需要 需要非模板庫。除此之外,您需要決定容器中的實際對象將在哪裏生存的 。如果他們都是 靜態物體(具有足夠的使用壽命),只需使用 a std::vector<TemplateInterface*>,並插入 v.push_back(&t1);等應該做的伎倆。否則, 您可能會想要支持克隆,並將克隆保存在 向量中:最好使用Boost指針容器,但也可以使用 std::shared_ptr

1

如果你正在尋找一個容器來存儲多種類型,那麼你應該從流行的boost庫中探索boost variant

2

到目前爲止給出的解決方案都很好,但請注意,如果您在示例中返回除bool之外的模板類型,則這些都不會有幫助,因爲vtable插槽無法在手動測量之前進行測量。從設計角度來看,實際上有限制使用面向模板的多態解決方案。

相關問題