我以为我已经理解了C ++中类模板的概念,但是看看我的代码我不再那么肯定了。假设我有两个类,一个非模板父项和一个模板作为子项,如下所示:
class MyParent
{
std::string m_Name;
MyParent(std::string Name) : m_Name(Name) { }
virtual const std::type_info& GetType() = 0;
};
template <class T>
class MyChild : public MyParent
{
T m_Var;
const std::type_info& GetType() override
{ return typeid(m_Var); }
};
现在在我的代码中,我有一个容器,其实例MyChild
使用不同的类型,例如:
MyParent* p1 = new MyChild<int>("one");
MyParent* p2 = new MyChild<float>("two");
MyParent* p3 = new MyChild<double>("three");
std::vector<MyParent*> v = {p1, p2, p3};
到目前为止,这很清楚,现在我的困惑开始了。假设我有一个迭代这个向量的函数,那么它需要对每个元素做一些事情。我刚刚编写的一些例子(我的问题不是代码本身,而是如何处理这种情况):
/* ... */
for(auto* p : v)
{
if(p->GetType() == typeid(int))
{
int val = p->m_Var;
std::list<int> lst = {val, 1, 2, 3};
if(val >= 0)
SomeTemplFuncPositive(v * v, lst); // a template variadic function
else
SomeTemplFuncNegative(v * v * -1, lst);
}
else if(p->GetType() == typeid(float))
{
/* ... now the same block c&p again for float? */
}
else if(p->GetType() == typeid(double))
{
/* ... and again for double?! */
}
}
/* ... */
在像Python这样的其他语言中,我只有一次这个代码块,但在C ++中我觉得我需要为float
再次复制整个代码块,并在{{1等等...
我不想责怪C ++,如果这是必须的,那么好吧。我只是想知道,在C ++中使用这样的构造时,这通常是正确的方法吗?
答案 0 :(得分:6)
您的virtual
- 需要调整:
class MyParent
{
std::string m_Name;
MyParent(std::string Name) : m_Name(Name) { }
virtual void doSomething()=0;
};
template <class T>
class MyChild : public MyParent
{
T m_Var;
void doSomething() override
{
T val = this->m_Var;
std::list<T> lst = {val, 1, 2, 3};
if (val >= 0)
SomeTemplFuncPositive(v * v, lst);
else
SomeTemplFuncNegative(v * v * -1, lst);
}
};
现在,您通过其基类调用doSomething()
:
for(auto* p : v)
{
p->doSomething();
}
一切都写得恰好一次。
答案 1 :(得分:0)
如果你需要从Base转换为Child,你的代码很可能是错误的(至少在C ++中)。当您存储指向衍生品的指针时,您应该确保不需要公开访问其特定成员(但虚拟方法仍然可以这样做)。在这种情况下,列表应以衍生方式声明,并将T
作为模板参数。
此外,您不需要GetType函数,可以使用dynamic_cast<DerivativeClass*>(baseClassPtr)
,如果转换正常则返回正确的指针,如果无法执行转换则返回nullp。