【发布时间】:2018-10-07 23:54:45
【问题描述】:
在开发数据导入系统时,我决定将大量派生自一个类的对象存储在指向父类的指针向量中。然后我想要一个函数,它返回任何类型的子指针的向量(使用让我知道它是什么类型的子指针的参数)。
我在这里设法实现了类似的简化代码,但它使用模板和强制转换,我觉得只有强制转换就足够了。但是编译器不想从向量 A* 到向量 B* 进行任何转换。
编辑:在实际代码中,有很多子类,而不仅仅是 B,所以用 B 替换模板不是一种选择,抱歉不够精确。
#include <vector>
using namespace std;
class A
{
public:
int attr;
A(): attr(1) {}
};
class B : public A
{
public:
B(): A() {attr = 2;}
};
template <typename O>
vector<O*> bees(vector<A*> vecA)
{
auto vecO = vector<O*>();
for (auto it = vecA.begin(); it != vecA.end(); it++)
{
if ((*it)->attr == 2)
{
vecO.push_back(reinterpret_cast<O*>(*it));
}
}
return vecO;
}
int main()
{
auto vecA = vector<A*>();
vecA.push_back(new A());
vecA.push_back(new B());
vecA.push_back(new B());
vector<B*> vecB = bees<B>(vecA);
}
所以我的问题是:是否可以在不使用模板的情况下让代码产生相同的效果?如果不是,编译器会用这个生成特定的代码吗?知道无论模板如何,理论上运行时都没有区别。
谢谢。
【问题讨论】:
-
你为什么使用
reinterpret_cast? -
我正在使用 reinterpret cast 因为它我不强制转换它只是不编译,而且我觉得它在这里是最合适的,因为我知道我不需要对对象进行任何更改.
-
这味道。
std::vector的原始指针是合理的,但在这里不是。您拥有 UB,因为您将指向A的指针转换为指向B的指针。而且您在调用bees时不必要地复制vecA,因为您不使用引用。这强烈地感觉你有一个 XY 问题。 -
通用基类的一般概念是它定义了一个所有派生类都遵循的接口。每当您觉得需要存储派生类的类型 (
attr) 以便您可以区别对待它们 时,这表明它们不 具有相同的接口.那么他们也不应该有一个共同的基类。你只是看到了这个问题的一个症状,“修复”这部分是治疗症状而不是疾病。 -
如果基类是多态的(即至少有一个虚成员函数),您可以使用
dynamic_cast来检查A*是否实际上指向O,并将结果推送到向量。如果您希望您的代码适用于从A派生的任何类,它要么需要是模板,要么需要为每个派生类显式重载。调用者还需要提供信息,以便编译器可以计算出要转换为的类型 - 使用重载函数,一种方法是提供一个额外的参数来提供类型信息。
标签: c++ templates pointers vector reinterpret-cast