推导纯虚函数的实现

时间:2013-12-12 16:08:02

标签: c++ polymorphism abstract-class pure-virtual virtual-method

考虑以下示例

#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抽象类,我该如何解决这个问题。

3 个答案:

答案 0 :(得分:11)

FunctionImpl::FunctionPureVirtual::Function是不同类别的不同功能。

他们各自的类型是void (FunctionImpl::*)()void (PureVirtual::*)() 由于PureVirtualFunctionImpl是不相关的类,因此这些函数类型不相关。

它们碰巧具有相同的名称和相同的参数以及返回类型,但由于它们不同,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();
    }
};

是的,it works as expected

答案 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