如何专门化基类中定义为纯函数的模板化函数?
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
类和所有派生类在未定义有效的virtual
func()
函数之前变得不可实例化。
定义
virtual void func(int a) {}
基A
类和所有派生类不再是不可实例化的,你不再需要重新定义虚函数。
但template
func()
版本与虚函数无关。
当你在main()
中调用b.func(2)
时,它是template
,而不是从A
继承的virtual
func()
。这是因为template
func()
"隐藏"func()
继承virtual
版本。
您可以在B
定义正文中添加B
"取消隐藏"virtual
func()
版本
using A::func;
这样,在main()
中调用b.func(2);
,调用A
继承的virtual
版本,并调用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
专业化中调用它
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 求解)
模板专用化 - 静态多态性(在编译时通过类型信息解决)
不要试图用另一个来解决一个。
在您的情况下,您正在尝试通过模板专用化为虚拟方法提供主体(解决运行时多态性)。