C++ 是否可以在函数中不使用模板而从向量父级*强制转换为向量子级*

C++ 是否可以在函数中不使用模板而从向量父级*强制转换为向量子级*,c++,templates,pointers,vector,reinterpret-cast,C++,Templates,Pointers,Vector,Reinterpret Cast,在处理数据导入系统时,我决定将从一个类派生的许多对象存储在指向父类的指针向量中。然后我想要一个函数,它返回任何类型的子指针的向量(使用参数让我知道它是什么类型的子指针) 我在这里实现了一个类似的简化代码,但它使用了模板和强制转换,我觉得只有强制转换就足够了。但是,编译器不希望执行从向量A*到向量B*的任何强制转换 编辑:在实际代码中有很多子类,不仅仅是B,所以用B替换模板不是一个选项,很抱歉不够精确 #include <vector> using namespace std; c

在处理数据导入系统时,我决定将从一个类派生的许多对象存储在指向父类的指针向量中。然后我想要一个函数,它返回任何类型的子指针的向量(使用参数让我知道它是什么类型的子指针)

我在这里实现了一个类似的简化代码,但它使用了模板和强制转换,我觉得只有强制转换就足够了。但是,编译器不希望执行从向量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);
}
#包括
使用名称空间std;
甲级
{
公众:
int attr;
A():attr(1){}
};
B类:公共A
{
公众:
B():A(){attr=2;}
};
模板
矢量蜜蜂(矢量蜜蜂)
{
自动向量=向量();
for(auto it=vecA.begin();it!=vecA.end();it++)
{
如果((*it)->attr==2)
{
vecO.推回(重新解释演员表(*it));
}
}
返回维科;
}
int main()
{
自动向量=向量();
vecA.push_back(新的A());
vecA.push_back(新B());
vecA.push_back(新B());
向量vecB=蜜蜂(vecA);
}
所以我的问题是:有没有可能让代码在不使用模板的情况下实现同样的效果?如果没有,编译器会用这个生成特定的代码吗?从理论上讲,无论模板是什么,运行时都不会有什么不同


谢谢。

因为您需要一个可以返回任何类型子指针向量的函数,所以我认为需要使用模板来指定子类型,但不需要重新解释转换等,下面是示例实现:

class A
{
  public:

    int attr;

    A(): attr(1) {}
    virtual ~A() {};
};

class B : public A
{
  public:

    B(): A() {attr = 2;}

};
template<typename T>
vector<T*> bees(const vector<A*> &vecA)
{
    vector<T*> vec;

    for (auto it = vecA.begin(); it != vecA.end(); it++)
    {
        T* ptr = dynamic_cast<T*>(*it);
        if(ptr != nullptr)
        {
          vec.push_back(*it);
        }
    }

    return vec;
}
A类
{
公众:
int attr;
A():attr(1){}
虚拟~A(){};
};
B类:公共A
{
公众:
B():A(){attr=2;}
};
模板
向量蜜蜂(const vector&vecA)
{
向量向量机;
for(auto it=vecA.begin();it!=vecA.end();it++)
{
T*ptr=动态投影(*it);
如果(ptr!=nullptr)
{
向量向后推(*it);
}
}
返回向量;
}

我们使用dynamic_cast是因为我们将父类型向下转换为子类型。同样,为了使dynamic_cast正常工作,我们需要虚拟析构函数/虚拟函数,因为它需要RTTI。继承和变形应该隐藏不同的子类型,所以代码的其余部分不必担心特定类型

将对象强制转换为特定类型很可能不是您尝试执行的任何操作的正确方法。让类型决定如何使用它们以及它们做什么,而不是外部世界

如果要过滤向量以仅获取具有特定属性的对象,则不应查看它们的类型,而应询问它们是否具有要查找的属性:

void FilterA(const std::vector<A>& source, std::vector<A>& destination, std::function<bool(const A&)> filter) {
    std::copy_if(source.begin(), source.end(), std::back_inserter(destination), filter);
}
void过滤器(const std::vector&source,std::vector&destination,std::function过滤器){
std::copy_if(source.begin()、source.end()、std::back_插入器(destination)、过滤器);
}
然后你可以这样称呼它:

std::vector<A> filteredVecA;
FilterA(vecA, filteredVecA, [](const A& a){return a.HasSomePropertyYouCareAbout();});
std::矢量滤波器;
FilterA(vecA,filteredVecA,[](const A&A){return A.hassomepropertyyoucareaout();});

< /代码> 您应该考虑在层次结构内移动类型检查(这使用模板,但没有强制转换):

A类{
公众:
virtual~A();//您在对象的层次结构中
模板
虚拟T*as()常量{return nullptr;}
};
模板
可转换类别:公共A{
模板
虚拟T*as()常量{
如果constexpr(std::is_same_v)
归还这个;
其他的
返回空ptr;
}
};
B类:公共敞篷车{
};
模板
矢量蜜蜂(矢量蜜蜂)
{
自动向量=向量();
foreach(自动ptr:vecA)
{
自动ptrO=ptr->as();
如果(ptrO)
向量推回(ptrO);
}
返回维科;
}
有几点:

OP评论:


我之所以使用reinterpret cast,是因为我不使用它,它只是不编译,而且我觉得它在这里是最合适的,因为我知道我不需要对对象做任何更改


dynamic\u cast
通常是类层次结构设计不足的症状。每当你认为“我可以用DyrimixCube来解决这个问题”时,就可以考虑将代码添加到类层次结构中。

为什么你使用了<代码> RealTytPase?我使用重译CAST,因为我不把它编译掉,在我看来,这是最充分的,因为我知道我不需要对物体做任何改变。这气味<原始指针的code>std::vector
可以被证明是正确的,但在这里不是。由于您将指向
a
的指针强制转换为指向
B
的指针,因此您具有UB。调用
bees
时不必要地复制
vecA
,因为您不使用引用。这给人的感觉很像是XY问题。通用基类的一般思想是它定义了一个所有派生类都遵循的接口。每当您觉得需要存储派生类的类型(
attr
)以便可以区别对待它们时,这表明它们没有相同的接口。那么它们也不应该有一个公共基类。您只看到了这个问题的一个症状,而“修复”这个部分治疗的是症状而不是疾病。如果基类是多态的(即至少有一个虚拟成员函数),您可以使用
dynamic\u cast
检查
A*
是否实际指向
O
,并将结果推送到向量中。如果您希望您的代码适用于从
A
派生的任何类,那么它需要是一个模板,或者每个派生类都需要显式重载。调用方还需要提供信息,以便编译器能够计算出类型b
class A {
public:
    virtual ~A(); // you _are_ in a hierarchy of objects

    template<typename T>
    virtual T* as() const { return nullptr; }
};

template<typename X>
class Convertible: public A {

    template<typename T>
    virtual T* as() const {
        if constexpr(std::is_same_v<X, T>)
            return this;
        else
            return nullptr;
    }
};

class B: public Convertible<B> {
};

template <typename O>
vector<O*> bees(vector<A*> vecA)
{
    auto vecO = vector<O*>();

    foreach (auto ptr: vecA)
    {
        auto ptrO = ptr->as<O>();
        if (ptrO)
            vecO.push_back(ptrO);
    }
    return vecO;
}