纯虚函数的模板专业化



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

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"中未实现的纯虚拟方法"func" 虚拟空隙函数(int a) = 0;

虚拟函数只能被非模板函数覆盖。在这种情况下,

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

请注意,函数模板不能是虚拟函数;

函数模板不能声明为虚拟模板。

从标准来看,[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
};

— 结束示例 ]

关于你的问题,

如果函数被设置为"不纯净",为什么它会起作用?

编译错误消失了,但它仍然无法按预期工作;派生类中的函数模板不会重写基类的虚拟函数。您可以通过动态调度进行检查:

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

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

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

您还可以应用覆盖说明符来帮助您确认覆盖

//virtual void func(int a) {}//用这个替换上面的行,它可以工作

替换上面的行和代码编译,不起作用。

或者,更好的是,有效,但不是你期望的那样。

问题是virtual函数和template函数不能很好地混合。

所以你不能做一个直接覆盖虚函数的模板函数:如果你func()定义为空虚函数

virtual void func(int a) = 0;

A类和所有派生类在未定义有效的virtualfunc()函数之前变得不可实例化。

定义

virtual void func(int a) {}

A类和所有派生类不再是不可实例化的,你不再需要重新定义虚函数。

templatefunc()版本与虚函数无关。

当你在main()中调用b.func(2)时,它是template,而不是从A继承的virtualfunc()。这是因为templatefunc()"隐藏"func()继承virtual版本。

您可以在B定义正文中添加B"取消隐藏"virtualfunc()版本

using A::func;

这样,在main()中调用b.func(2);,调用A继承的virtual版本,并调用func()的模板专用化,因此不再执行std::cout <<"hello 2" << std::endl;指令。

现在。。。如果我理解正确,您需要一个templatefunc()功能,以防T == int加入虚拟专业化。

我看到的唯一方法是定义virtualoverrideB

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

并从template专业化中调用它

template <>
void B::func<int> (int a)
{ func(a); } // call the virtual override version

以下是完整的编译示例

#include <iostream>
struct A
{ virtual void func(int a) = 0; };
struct B : public A
{
void func (int a) override
{ std::cout <<"hello 2" << std::endl; }
template<typename T>
void func (T t)
{ std::cout << "hello" << std::endl; }
};
template <>
void B::func<int> (int a)
{ func(a); }

int main ()
{
B{}.func(2); // call directly virtual func()
B{}.func<int>(2); // call template func() specialization that call virtual func()
}

除了重点之外,还可以考虑这一点,但是在使用模板进行设计时,您可以使用一个非常好的助记符:

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

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

不要试图用另一个来解决一个。

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

最新更新