向下转型`vector<Parent>`

3
我在我的程序中遇到了向上转型和向下转型的问题。我有一个 `vector`,它被传递给一个期望 `const vector& pp` 的函数中。在这里没有问题(编辑:显然是有问题的!请参见评论)。但是,现在我想将 `pp` 传递给一个期望 `const vector& cc` 的函数中,而我不能这样做。
在不给函数修改原始类的能力的同时,我该如何做到这一点?您能列出各种方法,并说明它们的优缺点吗?

6
第一步就已经存在问题,与你所说的相反。你无法做到这一点。 - Konrad Rudolph
2
你应该考虑使用vector<smart_ptr<Parent>>,根据你的使用情况选择合适的智能指针变体(unique_ptrshared_ptr)。这样,你仍然可以将Child对象存储在vector中,并将其传递给对元素进行多态操作的函数。 - Tony Delroy
@TonyD,谢谢。我决定按照你的建议使用智能指针。 - Eliad
4个回答

5
有一种叫做“变化”的东西,它有三种不同的形式:
- 不变性 - 即使B扩展了A,T也不会扩展T - 协变性 - 当B扩展A时,T将扩展T - 逆变性 - 当B扩展A时,T将扩展T 在使用C++模板时,您最终会得到不变性。即使按名称看起来相同:vector和vector这些是两种不同的类型。
如果您查看编译器生成的内容,它们都操作可能具有不同大小的类型。由于C++依赖于对象大小的知识(例如,当计算数组中对象位置时),类型如Child[]不能强制转换为Parent[],因为某些对象的位置可能会计算错误。出于同样的原因,模板的作用方式是不变的:编译器不能猜测何时进行此类转换是否安全。
因此,您需要解决这个问题,并且在这里有一些选项。其中一个是创建一个接受该参数模板的函数:
template<T>
void performAction(vector<T> objects) {
  // ...
}

另一种方法是使用(智能)指针替换值 - 它们可以轻松处理多态。

编辑:

为了说明我在最后一句话中的意思: 你可以简单地使用vector<unique_ptr<Parent>>vector<shared_ptr<Parent>>来存储任何Parent实例(包括Child),因此您不必执行容器的任何类型转换。


2
关于你最后一段的问题:vector<Parent*>vector<Child*>是完全无关的,你只能在所有地方都使用vector<Parent*> - molbdnilo
我确实是指你可以简单地使用vector<Parent*>来存储ParentChild的实例,这样转换类型就不会有问题。但是,是的,我没有说得很清楚。 - Mateusz Kubuszok
我怀疑过(而且应该说我怀疑过,而不是自以为是地去表现)。+1。 - molbdnilo

0

你可以使用一个模板函数 template func(vector vec) { //根据传入的对象类型做一些操作 }。向量是对象的容器,所以对于一个期望接收一个向量 &pp 的函数,如果我们传递 vector &&cc 将不起作用,代码甚至无法编译。

我们可以使用类似以下的代码:

class A
{
    int i;
};

class B : public A
{
    int j;
    int k;
};


template<class T> void f(vector<T> &p)
{
    //can handle both types now
}

int main()
{
    B b1;
    A a1;


    vector<A> vectorA;
    vectorA.push_back(a1);

    vector<B> vectorB;  
    vectorB.push_back(b1);

    f<B>(vectorB);

    f<A>(vectorA);
    return 0;
}

咦?这似乎与其他几个答案和评论对C++类型系统的说法直接相矛盾。 - David K
@DavidK 这是怎么回事?你能详细解释一下你的意思吗? - Nirmal Thakur
据我所知,以及其他答案和评论似乎也是这样说的,当期望使用vector<Parent>时,你不能使用vector<Child>。当然,你可以在期望使用Parent的地方使用Child,因为Child是从Parent派生出来的;但是vector<Child>并不是从vector<Parent>派生出来的。你是否写过一个函数,它接受了一个类似const vector<Parent> &&pp的参数,并将vector<Child>传递给它,它能按预期工作吗? - David K
@DavidK 你说得对。这样做是行不通的,因为它不适用于容器。所以一个正确的解决方案是使用模板函数,就像在这个问题的答案中建议的那样。 - Nirmal Thakur

0

你做不到。这是不可能的。

绝对不要这样做:

template<typename TBase, typename TChild>
const std::vector<TBase*>& downcast(const std::vector<TChild*>& children)
{
    static_assert(std::derived_from<TChild, TBase>);
    return *reinterpret_cast<const std::vector<TBase*>*>(&children);
}

0
即使Child是从Parent派生出来的,或者反过来,vector<Child>vector<Parent>是无关的,它们是不同的类型。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接