让多态基类insert在 stl 容器成员(本例中为向量)上有一个纯虚方法。该函数应该能够采用集合、向量、列表等容器的迭代器,但也要考虑引用的类型(移动语义)
函数的纯虚拟性质使得使用模板函数变得不可能。据我所知,stl 容器的迭代器是单独的类型,这就是模板有用的原因。然而,多态性是必要的。我还注意到 std::move_iterator 能够封装所有类型的迭代器。
\n是否还有其他“迭代器包装器”,我可以用它来在 Base 中定义纯虚拟方法,该方法接受各种迭代器,并且也像完美转发函数模板一样,以便客户端可以传递迭代器并移动迭代器?
\n在引入多态性之前,函数是这样的:
\nvector<Class> v;\ntemplate<typename Iter>\nvoid insert(Iter begin, Iter end) {\n v1.insert(begin, end, std::end(v));\n}\nRun Code Online (Sandbox Code Playgroud)\n但现在派生类在插入时的行为略有不同(互斥体、通知观察者等)。如果有类似下面的东西那就太好了:
\nvector<Class> v;\n\nvirtual void Base::insert(GenericIter begin, GenericIter end) = 0;\n\n[\xe2\x80\xa6]\n\nvoid DerivedMT::insert(GenericIter begin, GenericIter end) override\n{\n mutex.lock();\n v1.insert(begin, end, std::end(v));\n mutex.unlock();\n}\n\n[\xe2\x80\xa6]\n\nvoid DerivedObserved::insert(GenericIter begin, GenericIter end) override\n{\n v1.insert(begin, end, std::end(v));\n notifyObservers();\n}\nRun Code Online (Sandbox Code Playgroud)\n
您不能接受所有各种迭代器并维护运行时多态性,因为这样您就会违反里氏替换原则。也就是说,多态双向迭代器不适用于包装前向迭代器,因为后者只能递增。还有排序的关联容器,您不能使用其迭代器进行排序等:
因此,函数模板迭代器的目的是为接口实现者提供一种自由,让他可以在有两个迭代器的情况下做任何他想做的事情。但是使用运行时多态迭代器,您限制了实现者(您应该这样做)。
所以有两种方法:
insert(std::vector<YourType>)。这将处理您想要的所有通用迭代器,并且实现者可以自由地对该范围做任何他想做的事情。PolymorphicForwardIterator使用前向迭代器和类型擦除的特征来实现 const 。以下是如何在不进行堆分配的情况下删除类型的示例:
class PolymorphicReference final
{
public:
template <typename RefT>
explicit PolymorphicReference(RefT &ref)
: pVTable_(std::addressof(GetVTable(ref))),
ref_(std::addressof(ref))
{}
void Say(const std::string& msg)
{
pVTable_->pSay(ref_, msg);
}
int Number() const
{
return pVTable_->pNumber(ref_);
}
private:
struct VTable
{
virtual void pSay(void *pRef, const std::string& msg) = 0;
virtual int pNumber(const void *pRef) = 0;
protected:
~VTable() = default;
};
template <typename RefT>
static VTable &GetVTable(const RefT&)
{
struct : VTable
{
void pSay(void *pRef, const std::string& msg) override
{
static_cast<RefT*>(pRef)->Say(msg);
}
int pNumber(const void *pRef) override
{
return static_cast<const RefT*>(pRef)->Number();
}
} static vTable;
return vTable;
}
private:
VTable *pVTable_;
void *ref_;
};
Run Code Online (Sandbox Code Playgroud)