什么是C ++处理类模板及其类型的方法?

时间:2016-12-15 22:35:42

标签: c++ c++11

我以为我已经理解了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 ++中使用这样的构造时,这通常是正确的方法吗?

2 个答案:

答案 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。