纯虚函数的模板专业化

时间:2019-07-09 14:00:48

标签: c++ templates virtual-functions

如何专门化在基类中定义为纯函数的模板化函数?

struct A {
    virtual void func(int a) = 0;
    //virtual void func(int a) {} // replace above line with this and it works
};

struct B : public A {
    template<typename T> void func(T t) {
        cout <<"hello"<<endl;
    }
};
template<> void B::func<int>(int a) { cout <<"hello 2"<<endl; }


int main() {
    B b;
    b.func(2);
}

错误:

  

错误:变量类型'B'是抽象类       B b;         ^注意:“ B”中未实现的纯虚方法“ func”       虚拟虚空func(int a)= 0;

3 个答案:

答案 0 :(得分:5)

虚拟功能只能由非模板功能覆盖。在这种情况下,

  

然后Derived类中的此函数也是虚拟的(在声明中是否使用了关键字virtual),并覆盖了Base :: vf(在声明中是否使用了override这个词)。

请注意,功能模板不能为virtual functions

  

不能将功能模板声明为虚拟模板。

根据标准,[temp.mem]/4

  

成员函数模板的专业化不能覆盖   基类的虚函数。 [示例:

class B {
  virtual void f(int);
};

class D : public B {
  template <class T> void f(T); // does not override B​::​f(int)
  void f(int i) { f<>(i); }     // overriding function that calls the template instantiation
};
     

-示例]

关于您的问题,

  

如果将函数设为“不纯”,为什么会起作用?

消失了,但仍然无法正常工作。派生类中的函数模板不会覆盖基类的虚拟函数。您可以使用dynamic dispatch进行检查:

  

如果使用指针或对基类的引用来处理派生类,则对重写的虚函数的调用将调用派生类中定义的行为。

请注意,您应该使用指针或引用来进行动态调度,例如

B b;
A* pa = &b;
pa->func(2);

LIVE

您还可以应用override specifier来帮助您确认覆盖

答案 1 :(得分:1)

  

//virtual void func(int a) {} //用此替换上面的行,并且有效

替换上面的行,代码将无法编译。

或者,更好的方法是有效的,但是却没有您期望的那样。

问题在于virtual函数和template函数不能很好地融合。

因此,您不能创建直接覆盖虚拟函数的模板函数:如果将func()定义为空虚拟函数

virtual void func(int a) = 0;

在您没有定义有效的A virtual函数之前,基础func()类以及所有派生类将变得无法实例化。

定义

virtual void func(int a) {}

A基类以及所有派生类不再是不可实例化的,因为您不再需要重新定义虚拟函数。

但是template func()版本与虚函数无关。

当您在b.func(2)中调用main()时,将被称为template,而不是继承自virtual的{​​{1}} func()。这是因为A template“隐藏”了func()继承的func()版本。

您可以在virtual定义的主体中添加virtual中的func() B版本的“取消隐藏”

B

通过这种方式,在using A::func; 中调用b.func(2);,将调用main()继承的virtual版本,并A的模板特化,因此{{ 1}}指令,不再执行。

现在...如果我理解正确,那么您需要一个func() std::cout <<"hello 2" << std::endl;函数,以便在template的情况下加入虚拟专业化。

我看到的唯一方法是在func()中定义T == int virtual

override

并从B专长中调用它

void func (int a) override // override, so necessarily virtual
 { std::cout <<"hello 2" << std::endl; }  

以下是完整的编译示例

template

答案 2 :(得分:0)

这可能不是重点,但在使用模板进行设计时可以使用一个非常好的助记符:

虚拟函数-动态多态性(在运行时通过vtable解决)

模板专业化-静态多态性(在编译时通过类型信息解决)

不要试图彼此解决。

在您的情况下,您尝试通过模板专门化为虚拟方法提供主体(解决运行时多态性)。