考虑以下示例
#include <iostream>
struct PureVirtual {
virtual void Function() = 0;
};
struct FunctionImpl {
virtual void Function() {
std::cout << "FunctionImpl::Function()" << std::endl;
}
};
struct NonPureVirtual : public FunctionImpl, public PureVirtual {
using FunctionImpl::Function;
};
int main() {
NonPureVirtual c;
c.Function();
}
编译器(GCC 4.9,Clang 3.5)退出时出错
test.cpp:18:20: error: variable type 'NonPureVirtual' is an abstract class
NonPureVirtual c;
^
test.cpp:4:18: note: unimplemented pure virtual method 'Function' in 'NonPureVirtual'
virtual void Function() = 0;
^
但是当我没有得到形式PureVirtual
时,一切都还可以。这很奇怪,因为标准 10.4.4 表示
如果一个类包含或继承至少一个纯类,则它是抽象的 最终覆盖为纯虚拟的虚函数。
他们没有说明最终覆盖是什么,但我想它应该是FunctionImpl::Function()
,特别是当我通过using
指令使它可用时。那么为什么仍然是NonPureVirtual
抽象类,我该如何解决这个问题。
答案 0 :(得分:11)
FunctionImpl::Function
和PureVirtual::Function
是不同类别的不同功能。
他们各自的类型是void (FunctionImpl::*)()
和void (PureVirtual::*)()
由于PureVirtual
和FunctionImpl
是不相关的类,因此这些函数类型不相关。
它们碰巧具有相同的名称和相同的参数以及返回类型,但由于它们不同,using FunctionImpl::Function
行不会使该函数覆盖PureVirtual
中的函数。
如果您声明了void (PureVirtual::*)()
类型的变量,则无法为其指定FunctionImpl::Function
。
换句话说,PureVirtual::Function
的最终覆盖是PureVirtual
中的原始覆盖,它是纯虚拟的。
为了做出你想要的东西,Matthieu M.的回答(使用转发电话)是可行的方法,似乎。
答案 1 :(得分:5)
您不能使用using
指令,而是必须转而使用转发电话:
struct NonPureVirtual : public FunctionImpl, public PureVirtual {
virtual void Function() override {
return FunctionImpl::Function();
}
};
答案 2 :(得分:2)
你将使用声明归因于它没有做的事情。它的作用是(来自草案n3337,7.3.3 / 1):
... using-declaration在声明区域中引入了一个名称, using-declaration 出现在该声明区域中。
后来同一段:
如果 using-declaration 命名构造函数(3.4.3.1),它会隐式声明一组构造函数 出现 using-declaration 的类(12.9); 否则使用声明中指定的名称是a 在其他地方声明的某个实体名称的同义词。
在您的情况下,FunctionImpl::Function
首先在FunctionImpl
类中声明,它是其成员。使用声明不会改变这一事实,因为第16段进一步说明了这一点:
出于重载解析的目的, using-declaration 引入派生类的函数将被视为派生类的成员。特别是,隐式
this
参数应被视为指向派生类而不是基类的指针。 这对函数的类型没有影响,并且在所有其他方面,函数仍然是函数的成员 基类。
现在谈谈覆盖(10.3 / 2)的定义:
如果在类
vf
和类Base
中声明虚拟成员函数Derived
,直接或间接地从Base
派生,则成员函数{{1声明具有相同名称,参数类型列表(8.3.5),cv-quali fi cation和ref-quali fi er(或不存在相同)的vf
,然后Base::vf
也是虚拟的(无论是否如此声明)并且覆盖Derived::vf
。为方便起见,我们说任何虚函数都会覆盖它自己。
同一段落中还有最终覆盖者的定义。
类对象
Base::vf
的虚拟成员函数C::vf
是最终覆盖,除非其中S
的最派生类(1.8)是基础class subobject(如果有)声明或继承覆盖S
的另一个成员函数。在派生类中,如果基类子对象的虚拟成员函数具有多个最终覆盖,则程序格式不正确。 [...]
我认为这清楚表明你不能使用using声明来覆盖虚函数。可能的修复方法是Matthieu's answer。