关于c ++:覆盖模板方法

Overriding template methods

我正在尝试重写模板方法。下面是一个最小的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>

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

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

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


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是一个模板方法这一事实无关,而一切都与它不是虚拟的这一事实有关。不管print是什么,A::printB::print都不会被考虑。

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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!
"
;
    }        
};

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

对于简单的事情,比如流媒体,你也可以不需要图书馆就自己写。


虽然非特定化模板方法是虚拟的(例如,vtable会是什么样子?)值得指出的是,模板方法的专门化不可能是虚拟的,这对于允许它是非常有益的。我把它提交给C++委员会作为N3405中的最后一节。到目前为止,委员会还没有考虑到这一点,但我还有更老的文件要考虑,所以还是有希望的:)


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

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

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