纯虚函数的模板特化
Template specialization of pure virtual function
如何专门化在基 class 中定义为纯函数的模板化函数?
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);
}
错误:
error: variable type 'B' is an abstract class
B b;
^ note: unimplemented pure virtual method 'func' in 'B'
virtual void func(int a) = 0;
虚函数只能被 non-template 函数覆盖。在这种情况下,
Then this function in the class Derived is also virtual (whether or not the keyword virtual is used in its declaration) and overrides Base::vf (whether or not the word override is used in its declaration).
注意函数模板不能是virtual functions;
Functions templates cannot be declared virtual.
根据标准,[temp.mem]/4
A specialization of a member function template does not override a
virtual function from a base class. [ Example:
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
};
— end example ]
关于你的问题,
why it works if the function is made 'not pure'?
编译错误消失了,但仍然没有达到预期效果;派生 class 中的函数模板不会 覆盖 基础 class 的虚函数。您可以使用 dynamic dispatch:
检查
If a derived class is handled using pointer or reference to the base class, a call to an overridden virtual function would invoke the behavior defined in the derived class.
请注意,您应该使用指针或引用来进行动态调度,例如
B b;
A* pa = &b;
pa->func(2);
您也可以申请override specifier来帮助您确认覆盖。
//virtual void func(int a) {}
// replace above line with this and it works
替换上面的行,代码编译,不起作用。
或者,更好的是,有效,但不像您预期的那样。
问题是 virtual
函数和 template
函数不能很好地混合。
所以你不能制作直接覆盖虚函数的模板函数:如果你定义func()
为空虚函数
virtual void func(int a) = 0;
基础 A
class 和所有派生的 classes,变成 not-instantiable 直到你没有定义一个有效的 virtual
func()
函数。
正在定义
virtual void func(int a) {}
基础 A
class 和所有派生类不再是 not-instantiable 因为您不再需要重新定义虚函数。
但是template
func()
版本与虚函数无关
当你在main()
中调用b.func(2)
时,是template
,而不是继承自A
的virtual
func()
,即叫。这是因为 template
func()
"hide" func()
继承了 virtual
版本。
你可以"un-hide"在B
的virtual
func()
版本中添加,在B
的正文中定义
using A::func;
这样,在main()
中调用b.func(2);
,调用A
继承的virtual
版本和func()
的模板特化,所以std::cout <<"hello 2" << std::endl;
指令,不再执行。
现在...如果我理解正确的话,你想要一个 template
func()
函数,以防 T == int
加入虚拟专业化。
我看到的唯一方法是在 B
中定义 virtual
override
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在运行时解决)
模板特化-静态多态(在编译时通过类型信息解决)
不要试图用一个来解决另一个。
在您的情况下,您正试图通过模板特化向虚方法提供主体(解决运行时多态性)。
如何专门化在基 class 中定义为纯函数的模板化函数?
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);
}
错误:
error: variable type 'B' is an abstract class B b; ^ note: unimplemented pure virtual method 'func' in 'B' virtual void func(int a) = 0;
虚函数只能被 non-template 函数覆盖。在这种情况下,
Then this function in the class Derived is also virtual (whether or not the keyword virtual is used in its declaration) and overrides Base::vf (whether or not the word override is used in its declaration).
注意函数模板不能是virtual functions;
Functions templates cannot be declared virtual.
根据标准,[temp.mem]/4
A specialization of a member function template does not override a virtual function from a base class. [ Example:
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 };
— end example ]
关于你的问题,
why it works if the function is made 'not pure'?
编译错误消失了,但仍然没有达到预期效果;派生 class 中的函数模板不会 覆盖 基础 class 的虚函数。您可以使用 dynamic dispatch:
检查If a derived class is handled using pointer or reference to the base class, a call to an overridden virtual function would invoke the behavior defined in the derived class.
请注意,您应该使用指针或引用来进行动态调度,例如
B b;
A* pa = &b;
pa->func(2);
您也可以申请override specifier来帮助您确认覆盖。
//virtual void func(int a) {}
// replace above line with this and it works
替换上面的行,代码编译,不起作用。
或者,更好的是,有效,但不像您预期的那样。
问题是 virtual
函数和 template
函数不能很好地混合。
所以你不能制作直接覆盖虚函数的模板函数:如果你定义func()
为空虚函数
virtual void func(int a) = 0;
基础 A
class 和所有派生的 classes,变成 not-instantiable 直到你没有定义一个有效的 virtual
func()
函数。
正在定义
virtual void func(int a) {}
基础 A
class 和所有派生类不再是 not-instantiable 因为您不再需要重新定义虚函数。
但是template
func()
版本与虚函数无关
当你在main()
中调用b.func(2)
时,是template
,而不是继承自A
的virtual
func()
,即叫。这是因为 template
func()
"hide" func()
继承了 virtual
版本。
你可以"un-hide"在B
的virtual
func()
版本中添加,在B
的正文中定义
using A::func;
这样,在main()
中调用b.func(2);
,调用A
继承的virtual
版本和func()
的模板特化,所以std::cout <<"hello 2" << std::endl;
指令,不再执行。
现在...如果我理解正确的话,你想要一个 template
func()
函数,以防 T == int
加入虚拟专业化。
我看到的唯一方法是在 B
virtual
override
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在运行时解决)
模板特化-静态多态(在编译时通过类型信息解决)
不要试图用一个来解决另一个。
在您的情况下,您正试图通过模板特化向虚方法提供主体(解决运行时多态性)。