【发布时间】:2012-05-25 17:52:14
【问题描述】:
我正在尝试在 C++(11) 中实现类似集合类的 .NET 框架。我的问题是无效的协变类型。我有这些课程:
template<typename T>
class IEnumerator
{
public:
virtual bool MoveNext() = 0;
//...
};
template<typename T>
class IEnumerable
{
virtual IEnumerator<T> GetEnumerator() = 0;
};
template<typename T>
class List : public IEnumerable<T>
{
public:
struct Enumerator : public IEnumerator<T>
{
Enumerator(List<T> &list)
{
//...
}
// ...
};
Enumerator GetEnumerator()
{
return Enumerator(*this);
}
};
在我看来,这太棒了。但是在 C++ 中实现它看起来是不可能的。我得到 g++ 的“无效协变返回类型”,据我所知,问题是 GetEnumerator 可能只返回一个指针或对 Enumerator 的引用,而不是 Enumerator 本身的对象。
我想避免返回这样的指针:
Enumerator *GetEnumerator()
{
return new Enumerator(*this);
}
因为我不希望调用者打扰删除。使用临时对象,我可以确保该对象被自动删除,因为它不再需要了。使用引用可能会更糟。
我错过了什么吗?还是 C++ 标准(和语言)存在巨大漏洞?我真的很想实现这样的目标。
提前致谢。
【问题讨论】:
-
啊!
IEnumerable是对 C++ 迭代器的糟糕改造;为什么要在 C++ 中使用它?在任何情况下,.NET 都使用引用语义,因此要在 C++ 中模仿这一点,您必须使用引用或指针——这并不奇怪。 -
这是不可能用价值语言实现的。
-
@ildjarn 我觉得很好,这样我就可以在函数参数中使用 IEnumerable,无论后面的类型是什么(向量、链表、RB-tree)它仍然是 IEnumerable,它有返回 IEnumerator 的 GetEnumerator() 函数。您可以将 vector
和 list 都传递给没有共同祖先的同一个函数吗? -
@AlfaOmega08: 是的,你可以编写一个函数(模板),它可以使用
list<T>和vector<T>,而不会出现任何问题——但你几乎不应该这样做。相反,它通常应该采用一对迭代器(或一个范围)。标准库有很多示例(例如,std::accumulate、std::sort、std::find、std::lower_bound等) -
顺便说一句,作为返回调用者必须删除的新 T* 的安全替代方法,您可以返回 std::shared_ptr
,它会在所有引用被删除时自动删除已失效。
标签: c++ pointers ienumerable return-type covariant