2012-11-08 59 views
3

我對模板參數有一個相當簡單的問題。我正在寫使用列表如下一類調度:繼承和模板參數

list<PartitionT<CompareJobReady, CompareJobRunning> > partitions; 

PartitionT是使用priority_queues一個模板類,我想parametrise使用比較類這些隊列。 CompareJobReady和CompareJobRunning是這些類(它們實現特定的運算符())。

無論如何,由於PartitionT是一個模板類,我希望能夠傳遞任何類型的比較器類。特別是,我定義了兩個額外的類,即CompareJobReadyEDFVD(繼承自CompareJobReady)和CompareJobRunningEDFVD(繼承自CompareJobRunning)。

我真的想現在要做的,是能寫出這樣的事:

list<PartitionT<CompareJobReady, CompareJobRunning> > *p = new list<PartitionT<CompareJobReadyEDFVD, CompareJobRunningEDFVD> >(); 

但是,編譯器告訴我轉換是不可能的。我的問題最好的解決方案是什麼?

+1

這是來自標準庫的'std :: list'嗎? – dyp

+0

是的,如果我沒有提到它,對不起。 – user1809140

回答

0

對類型使用模板,但對行爲使用繼承。提供一個構造成可以傳遞構造比較類(如模板參數類型),如

list<PartitionT<CompareJobReady, CompareJobRunning> > *p = 
    new list<PartitionT<CompareJobReady, CompareJobRunning> >( 
    new CompareJobReadyEDFVD(), new CompareJobRunningEDFVD()); 
+0

如果這是一個std列表,ctor對於'list'是不正確的。你可以使用[initializer-list](http://en.cppreference.com/w/cpp/container/list/list)(7)。 – dyp

+0

我不確定這是否解決了我的問題,因爲我必須將類本身傳遞給priority_queue,而不是類的實例: – user1809140

+0

但是比較器完全是**獨立的**類模板參數,它與'std :: priority_queue'。你甚至可以在你的'PartitionT'模板類中使用它嗎?如果沒有,就把它消除。 –

1

標準庫自己其元件的容器類。也就是說,如果您有:

class Base {}; 
class Child : public Base {}; 

std::list <Base> myList; 
std::list <Base> *pMyList; 

隨後的myList的元素只能爲(引用)Base類型的對象進行訪問。您可以存儲Base類型的元素(例如push_backemplace_back),並獲取參考/副本(例如front或通過迭代器),例如,請參見cppreference/list。讓我們來看看push_back

void push_back(const value_type&); 

哪裏value_type是你傳遞給std::list第一個模板參數。在你的情況下,這是PartitionT < CompareJobReady, CompareJobRunning >,或在上面的例子中,它是Basepush_back實際上副本您傳遞的參數並使該副本成爲新元素。這是爲什麼?因爲新元素可以歸列表所有。列表可以在列表本身被銷燬時銷燬該元素,並且如果您移動/交換兩個列表,則將它傳遞給另一個列表。如果元素沒有被複制並從外部銷燬,則列表將包含一個被破壞的元素 - 這會破壞列表給出的保證(並且它不會很好)。

另一個示例(簡化,不是很準確):list通過分配器爲其元素分配內存。這裏的默認分配器是std::allocator<Base>。它僅爲存儲類型爲Base的對象所需的元素分配儘可能多的內存。

當你做這樣的事情pMyList = new std::list <Child>;,右側的結果是「指針std::list<Child>」,而左側的類型是「指向std::list<Base>」。這兩種類型無關,因爲std::list<Base>不會繼承或定義轉換爲std::list<Child>。有一些原因爲什麼這很好,一個是泛型​​編程需要知道它處理的是什麼類型。多態是一種抽象,所以你不必在編譯時知道你正在處理的是什麼類型。

C++中的多態性通過指針或引用工作。所以,如果你想安排在不可知這種類型的列表中的一些Child對象(例如只知道Base類型),您必須將它們存儲爲指針:

std::list < std::shared_ptr<Base> > myList2; 

myList2.push_back(new Child); // better not use, there's a caveat (1) 

// approach w/o this caveat 
std::shared_ptr<Base> pNewChild(new Child); // or make_shared 
myList2.push_back(pNewChild); 

注意我這裏使用shared_ptr,你可以使用一個unique_ptr如果這適合你更好的目的,但你不應該使用原始ptrs:因爲這myList2擁有它的shared_ptr元素和shared_ptr擁有共享所有權的對象(類型爲Base),myList2間接擁有Child將ptrs存儲在列表中的對象。由於原料ptrs不表示所有權,例如誰不負責銷燬它們。閱讀更多關於"Rule of Zero"

(1)有一個警告,請參閱boost,雖然它不影響此示例。


如果你真的想選擇的地方比較程序類來完成泛型編程,你「必須堅持編譯時間」:您的列表類型(type *p)不應該被固定爲list<Base>,而是通用(使用模板)以及您在其上使用的所有算法都必須是通用的。你不能(簡單地*)混合泛型編程和類型的運行時選擇,因爲泛型編程就是在編譯時創建代碼。

*有一個黑客,它允許它,濫用RTTI,因此非常緩慢。