向下转换`vector<Parent>`
Downcasting `vector<Parent>`
我在程序中遇到向上转型和向下转型的问题。我有一个 vector<Child>
传递给期望 const vector<Parent>& pp
的函数。到目前为止没有问题(编辑:显然有!请参阅评论)。但是,现在我想将 pp
传递给期望 const vector<Child>& cc
的函数,但我不能这样做。
我应该怎么做,同时我又不给函数修改原来的能力类?您能否列出各种方法,最好列出它们的优缺点?
即使 Child
派生自 Parent
或相反,vector<Child>
和 vector<Parent>
也不相关,它们是不同的类型。
有一种东西叫做变异。它有 3 种口味:
- 不变性 - 即使
B
扩展了 A
,T<B>
没有扩展 T<A>
,
- 协变 - 当
B
扩展A
,然后T<B>
扩展T<A>
,
- 逆变 - 当
B
扩展 A
,然后 T<A>
扩展 T<B>
.
当涉及到 C++ 模板时,您最终会遇到不变性。尽管名字看起来一样:vector<Parent>
和 vector<Child>
它们是两种不同的类型。
如果您查看编译器生成的内容,它们都对可能具有不同大小的类型进行操作。由于 C++ 依赖于对象大小的知识(例如,当它计算对象在数组中的位置时)类型,例如Child[]
无法转换为 Parent[]
,因为某些对象的位置可能计算错误。出于同样的原因,模板以不变的方式运行:编译器无法猜测何时会以及何时执行此类转换是不安全的。
因此,您可以自行解决这个问题,这里有一些选择。一种方法是制作也采用该参数模板的函数:
template<T>
void performAction(vector<T> objects) {
// ...
}
其他人会用(智能)指针替换值 - 他们会轻松处理多态性。
编辑:
为了说明我在最后一句话中的意思:您可以简单地使用 vector< unique_ptr<Parent> >
或 vector< shared_ptr<Parent> >
来存储 Parent
的任何实例(包括 Child
),所以您不必对容器进行任何转换。
你可以有一个模板函数 template func(vector vec) { //根据传递的对象类型做一些事情}。向量是对象的容器,因此对于期望向量 &pp 的函数,如果我们传递向量 && 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;
}
我在程序中遇到向上转型和向下转型的问题。我有一个 vector<Child>
传递给期望 const vector<Parent>& pp
的函数。到目前为止没有问题(编辑:显然有!请参阅评论)。但是,现在我想将 pp
传递给期望 const vector<Child>& cc
的函数,但我不能这样做。
我应该怎么做,同时我又不给函数修改原来的能力类?您能否列出各种方法,最好列出它们的优缺点?
即使 Child
派生自 Parent
或相反,vector<Child>
和 vector<Parent>
也不相关,它们是不同的类型。
有一种东西叫做变异。它有 3 种口味:
- 不变性 - 即使
B
扩展了A
,T<B>
没有扩展T<A>
, - 协变 - 当
B
扩展A
,然后T<B>
扩展T<A>
, - 逆变 - 当
B
扩展A
,然后T<A>
扩展T<B>
.
当涉及到 C++ 模板时,您最终会遇到不变性。尽管名字看起来一样:vector<Parent>
和 vector<Child>
它们是两种不同的类型。
如果您查看编译器生成的内容,它们都对可能具有不同大小的类型进行操作。由于 C++ 依赖于对象大小的知识(例如,当它计算对象在数组中的位置时)类型,例如Child[]
无法转换为 Parent[]
,因为某些对象的位置可能计算错误。出于同样的原因,模板以不变的方式运行:编译器无法猜测何时会以及何时执行此类转换是不安全的。
因此,您可以自行解决这个问题,这里有一些选择。一种方法是制作也采用该参数模板的函数:
template<T>
void performAction(vector<T> objects) {
// ...
}
其他人会用(智能)指针替换值 - 他们会轻松处理多态性。
编辑:
为了说明我在最后一句话中的意思:您可以简单地使用 vector< unique_ptr<Parent> >
或 vector< shared_ptr<Parent> >
来存储 Parent
的任何实例(包括 Child
),所以您不必对容器进行任何转换。
你可以有一个模板函数 template func(vector vec) { //根据传递的对象类型做一些事情}。向量是对象的容器,因此对于期望向量 &pp 的函数,如果我们传递向量 && 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;
}