重写模板方法

Overriding template methods

本文关键字:模板方法 重写      更新时间:2023-10-16

我正在尝试覆盖模板方法。下面是一个最小示例:

#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定义它,它将按预期工作(已经尝试过(,但它需要是一个模板。那么我做错了什么?

两个调用调用Base::print的原因与print是一个模板方法这一事实无关,而与它是非虚拟的事实有关。不管是什么printA::printB::print都不会被考虑在内。

现在,通过Base*实际调用A::print的典型解决方案是简单地使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";
    }
};

对于像流式传输这样简单的事情,您也可以自己编写,而无需库。

First 成员函数模板不能是虚拟的

,派生类中的成员函数模板不能重写基类中的虚拟成员函数。

作为您的代码,指针的类型为 Base*,因此在模板成员函数实例化中,Base 中的函数被实例化,这就是调用函数 is base 的原因。

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

虽然非专用模板方法是虚拟的(例如,vtable会是什么样子?(,但值得指出的是,模板方法的专业化没有理由不是虚拟的,并且允许它有很大的好处。我将其作为 N3405 的最后一部分提交给C++委员会。委员会尚未考虑这一点,但我有更老的论文要考虑,所以仍然有希望:)