派生纯虚函数的实现

Deriving implementation of pure virtual function

本文关键字:实现 函数 派生      更新时间:2023-10-16

考虑以下示例

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

FunctionImpl::FunctionPureVirtual::Function是来自不同类的不同函数。

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

它们

碰巧具有相同的名称、相同的参数和返回类型,但由于它们不同,因此using FunctionImpl::Function行不会使该函数覆盖 PureVirtual 中的函数。

如果你声明了一个类型 void (PureVirtual::*)() 的变量,你将无法FunctionImpl::Function赋给它。

换句话说,PureVirtual::Function的最终覆盖是PureVirtual中的原始覆盖,它是纯虚拟的。

为了让你想要的东西成为可能,Matthieu M.的答案(使用转接电话(似乎是要走的路。

您不能使用 using 指令,而必须求助于调用:

struct NonPureVirtual : public FunctionImpl, public PureVirtual {
    virtual void Function() override {
        return FunctionImpl::Function();
    }
};

是的,它按预期工作。

你用它不做的事情来归因于一个 using 声明。它的作用是(来自草案 n3337,7.3.3/1(:

。使用声明将名称引入到出现使用声明的声明性区域中。

后来来自同一段:

如果 using 声明命名构造函数 (3.4.3.1(,它将隐式声明一组构造函数 出现使用声明的类 (12.9(;否则,在 using-声明中指定的名称为 在其他地方声明的某个实体的名称的同义词。

在您的情况下,FunctionImpl::Function首先在类中声明FunctionImpl并且它是其成员。使用声明不会改变这一事实,正如第16段所说:

出于重载解析的目的,由 using-声明引入派生类的函数将被视为派生类的成员。特别是,应将隐式 this 参数视为指向派生类而不是基类的指针。 这对函数的类型没有影响,并且在所有其他方面,函数仍然是 基类。

现在来看覆盖的定义 (10.3/2(:

如果一个虚成员函数vf在类Base和类Derived中声明,直接或间接派生自Base,一个成员函数vf与声明Base::vf具有相同的名称、参数类型列表(8.3.5(、cv-限定符和ref限定符(或没有相同(,那么Derived::vf也是虚拟的(无论它是否如此声明(,它覆盖Base::vf。为了方便起见,我们说任何虚拟函数都会覆盖自身。

在同一段中还有最终覆盖器的定义。

类对象的虚拟成员函数C::vf S最终覆盖器,除非派生最多的类 (1.8((其中S是基类子对象(如果有(声明或继承另一个重写vf的成员函数。在派生类中,如果基类子对象的虚拟成员函数具有多个最终重写程序,则程序格式不正确。[...]

我认为这清楚地表明您不能使用 using 声明来覆盖虚函数。一个可能的解决办法是在马修的回答中。