标准库的容器类拥有它们的元素。也就是说,如果您有:
class Base {};
class Child : public Base {};
std::list < Base > myList;
std::list < Base > *pMyList;
那么 的元素myList
只能作为(引用)类型的对象来访问Base
。您可以存储类型的元素Base
(例如push_back
, )并获取(例如,或通过迭代器)emplace_back
的引用/副本,例如,请参阅cppreference/list。让我们来看看:front
push_back
void push_back(const value_type&);
value_type
您传递给的第一个模板参数在哪里std::list
。在您的情况下,即PartitionT < CompareJobReady, CompareJobRunning >
,或者在上面的示例中,它是Base
。
push_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
这里使用 a,unique_ptr
如果更适合您的目的,您也可以使用 a,但您不应该使用原始 ptrs:因为 thismyList2
拥有它的shared_ptr
元素并且 ashared_ptr
拥有一个共享所有权的对象(类型为 Base),myList2
因此间接拥有Child
您在列表中存储 ptrs 的对象。由于原始 ptr 不表示所有权,因此谁负责销毁它们并不明显。阅读有关“零规则”的更多信息。
(1) 有一个警告,尽管它不影响这个例子,但请参阅boost 。
如果你真的想通过在某个地方选择 Comparer 类来进行通用编程,你“必须坚持编译时间”:你的列表类型(类型*p
)不应该固定,list<Base>
而是通用(使用模板)和你的所有算法使用它也必须是通用的。您不能(简单地*)混合泛型编程和运行时类型的选择,因为泛型编程就是在编译时创建代码。
*有一个允许它的黑客,滥用 RTTI,因此非常慢。