这不起作用,因为
- 您没有返回指针或引用,这是协变返回工作所必需的;和
Foo<B>
并且Foo<B>
不管Foo
,A
和都没有继承关系B
(除非有专门化使它如此)。
但我们可以解决这个问题。首先,请注意std::vector<A*>
和std::vector<B*>
不能相互替代,无论任何语言限制,仅仅是因为std::vector<B*>
不支持A*
向其添加元素。所以你甚至不能编写一个自定义适配器来std::vector<B*>
代替std::vector<A*>
但是 的只读容器B*
可以修改为看起来像 的只读容器A*
。这是一个多步骤的过程。
创建一个抽象类模板,导出一个只读的容器类接口
template <class ApparentElemType>
struct readonly_vector_view_base
{
struct iter
{
virtual std::unique_ptr<iter> clone() const = 0;
virtual ApparentElemType operator*() const = 0;
virtual iter& operator++() = 0;
virtual iter& operator--() = 0;
virtual bool operator== (const iter& other) const = 0;
virtual bool operator!= (const iter& other) const = 0;
virtual ~iter(){}
};
virtual std::unique_ptr<iter> begin() = 0;
virtual std::unique_ptr<iter> end() = 0;
virtual ~readonly_vector_view_base() {}
};
它返回指向迭代器的指针,而不是迭代器本身,但不用担心,无论如何,此类只会被类似 STL 的包装器使用。
readonly_vector_view_base
现在为及其迭代器创建一个具体的包装器,以便它包含一个指向 a 的指针,并将其操作委托给 a readonly_vector_view_base
。
template <class ApparentElemType>
class readonly_vector_view
{
public:
readonly_vector_view(const readonly_vector_view& other) : pimpl(other.pimpl) {}
readonly_vector_view(std::shared_ptr<readonly_vector_view_base<ApparentElemType>> pimpl_) : pimpl(pimpl_) {}
typedef typename readonly_vector_view_base<ApparentElemType>::iter iter_base;
class iter
{
public:
iter(std::unique_ptr<iter_base> it_) : it(it_->clone()) {}
iter(const iter& other) : it(other.it->clone()) {}
iter& operator=(iter& other) { it = other.it->clone(); return *this; }
ApparentElemType operator*() const { return **it; }
iter& operator++() { ++*it; return *this; }
iter& operator--() { --*it; return *this; }
iter operator++(int) { iter n(*this); ++*it; return n; }
iter operator--(int) { iter n(*this); --*it; return n; }
bool operator== (const iter& other) const { return *it == *other.it; }
bool operator!= (const iter& other) const { return *it != *other.it; }
private:
std::unique_ptr<iter_base> it;
};
iter begin() { return iter(pimpl->begin()); }
iter end() { return iter(pimpl->end()); }
private:
std::shared_ptr<readonly_vector_view_base<ApparentElemType>> pimpl;
};
现在创建一个模板化实现,用于readonly_vector_view_base
查看不同类型元素的向量:
template <class ElemType, class ApparentElemType>
struct readonly_vector_view_impl : readonly_vector_view_base<ApparentElemType>
{
typedef typename readonly_vector_view_base<ApparentElemType>::iter iter_base;
readonly_vector_view_impl(std::shared_ptr<std::vector<ElemType>> vec_) : vec(vec_) {}
struct iter : iter_base
{
std::unique_ptr<iter_base> clone() const { std::unique_ptr<iter_base> x(new iter(it)); return x; }
iter(typename std::vector<ElemType>::iterator it_) : it(it_) {}
ApparentElemType operator*() const { return *it; }
iter& operator++() { ++it; return *this; }
iter& operator--() { ++it; return *this; }
bool operator== (const iter_base& other) const {
const iter* real_other = dynamic_cast<const iter*>(&other);
return (real_other && it == real_other->it);
}
bool operator!= (const iter_base& other) const { return ! (*this == other); }
typename std::vector<ElemType>::iterator it;
};
std::unique_ptr<iter_base> begin() {
iter* x (new iter(vec->begin()));
std::unique_ptr<iter_base> y(x);
return y;
}
std::unique_ptr<iter_base> end() {
iter* x (new iter(vec->end()));;
std::unique_ptr<iter_base> y(x);
return y;
}
std::shared_ptr<std::vector<ElemType>> vec;
};
好的,只要我们有两种类型,其中一种可以转换为另一种类型,例如A*
and B*
,我们就可以将 的向量B*
视为 的向量A*
。
但它给我们带来了什么?readonly_vector_view<A*>
还是无关的readonly_vector_view<B*>
!继续阅读...
事实证明,协变返回类型并不是真正必要的,它们是 C++ 中可用的语法糖。假设 C++ 没有协变返回类型,我们可以模拟它们吗?其实很简单:
class Base
{
virtual Base* clone_Base() { ... actual impl ... }
Base* clone() { return clone_Base(); } // note not virtual
};
class Derived : public Base
{
virtual Derived* clone_Derived() { ... actual impl ... }
virtual Base* clone_Base() { return clone_Derived(); }
Derived* clone() { return clone_Derived(); } // note not virtual
};
它实际上很简单,返回类型不需要是指针或引用,或者具有继承关系。有一个转换就足够了:
class Base
{
virtual shared_ptr<Base> clone_Base() { ... actual impl ... }
shared_ptr<Base> clone() { return clone_Base(); }
};
class Derived : public Base
{
virtual shared_ptr<Derived> clone_Derived() { ... actual impl ... }
virtual shared_ptr<Base> clone_Base() { return clone_Derived(); }
shared_ptr<Derived> clone() { return clone_Derived(); }
};
以类似的方式,我们可以安排A::test()
返回 areadonly_vector_view<A*>
和B::test()
返回 a readonly_vector_view<B*>
。由于这些函数现在不是虚拟的,因此不需要它们的返回类型有任何关系。一个只是隐藏另一个。但是在内部,他们调用了一个虚函数,该函数创建(比如说)一个readonly_vector_view<A*>
根据 实现的readonly_vector_view_impl<B*, A*>
实现vector<B*>
,并且一切都像真正的协变返回类型一样工作。
struct A
{
readonly_vector_view<A*> test() { return test_A(); }
virtual readonly_vector_view<A*> test_A() = 0;
};
struct B : A
{
std::shared_ptr<std::vector<B*>> bvec;
readonly_vector_view<B*> test() { return test_B(); }
virtual readonly_vector_view<A*> test_A() {
return readonly_vector_view<A*>(std::make_shared<readonly_vector_view_impl<B*, A*>>(bvec));
}
virtual readonly_vector_view<B*> test_B() {
return readonly_vector_view<B*>(std::make_shared<readonly_vector_view_impl<B*, B*>>(bvec));
}
};
小菜一碟!现场演示完全值得努力!