覆盖模板方法

时间:2014-12-16 13:33:39

标签: c++ templates inheritance

我正在尝试覆盖模板方法。 这是一个最小的例子:

#include <iostream>

class Base
{
public:
    template <typename T>
    void print(T var)
    {
        std::cout << "This is a generic place holder!\n";
    }
};

class A: public Base
{
public:
    template <typename T>
    void print(T var)
    {
        std::cout << "This is A printing " << var << "\n";
    }
};

class B: public Base
{
public:
    template <typename T>
    void print(T var)
    {
        std::cout << "This is B printing " << var << "\n";
    }
};


int main()
{
    Base * base[2];
    base[1] = new A;
    base[2] = new B;

    base[1]->print(5);
    base[2]->print(5);

    delete base[1];
    delete base[2];
    return 0;
}

两种情况下的输出This is a generic place holder! 我怎样才能实现派生类的方法被调用?

如果该方法不是模板,我可以定义它virtual,它可以按预期工作(已经尝试过),但它需要是一个模板。我做错了什么?

3 个答案:

答案 0 :(得分:2)

调用Base::print这两个调用的原因与print是模板方法以及与非虚拟事实有关的事实无关。无论print是什么,A::printB::print都不会被考虑。

现在通过A::print实际调用Base*的典型解决方案是简单地使print成为virtual方法。但是,这是禁止的,因为print是一个模板,您不能通过规则获得模板虚拟方法。

解决这个问题的一种方法是类型擦除。您可以使用Boost.TypeErasure执行以下操作:

typedef any<mpl::vector<
    copy_constructible<>,
    typeid_<>,
    ostreamable<>
> > any_streamable;

struct Base {
    virtual void print(any_streamable var) // not a template!
    {
        std::cout << "This is a generic place holder!\n";
    }        
};

struct A : Base {
    void print(any_streamable var) {
        std::cout << "This is A printing " << var << "\n";
    }
};

对于像流媒体这样的简单事物,你也可以自己写作而不需要图书馆。

答案 1 :(得分:1)

首先,成员函数模板不能是虚拟的,派生类中的成员函数模板不能覆盖基类中的虚拟成员函数。

作为你的代码,指针的类型是Base *,所以在模板成员函数实例化中,Base中的函数被实例化,这就是函数为base的原因。

如果使用A *和B *,子实例中的函数将被实例化并调用。

答案 2 :(得分:1)

虽然非特定模板方法是虚拟的没有意义(例如,vtable会是什么样子?),但值得指出的是,模板方法的专业化没有理由不是虚拟的,允许它的重大好处。我将此作为N3405的最后一部分提交给C ++委员会。委员会尚未考虑过这个问题,但我甚至有更旧的论文需要考虑,所以仍有希望:)