使用非纯虚拟版本重载纯虚函数

Mil*_*ilo 10 c++

使用Base和Derived定义如下:

class Base {

    public:
        virtual int f1(int a) const = 0;
        virtual int f2(int a, int b) const { return a+b;}
};

class Derived : public Base {

    public:
        int f1(int a) const { return a; }
}; 

int main() {
    Derived obj;
    cout << obj.f1(1) << endl;
    cout << obj.f2(1, 2) << endl;
}
Run Code Online (Sandbox Code Playgroud)

结果是

1
3
Run Code Online (Sandbox Code Playgroud)

obj.f1(1)使用Derivedf1实现,而obj.f2(1,2)使用从Base继承的实现,这就是我想要的.

现在,我希望这两个函数具有相同的名称f,因此当有两个参数且派生类必须实现单个参数版本时,基类提供了一个实现(这就是为什么它是纯虚拟的).

但是,如果我这样做(只需将f1f2重命名为f):

class Base {

    public:
        virtual int f(int a) const = 0;
        virtual int f(int a, int b) const { return a + b;}
};

class Derived : public Base {

    public:
        int f(int a) const { return a; }
};

int main() {
    Derived obj;
    cout << obj.f(1) << endl;
    cout << obj.f(1, 2) << endl;
}
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

20:23: error: no matching function for call to 'Derived::f(int, int)'
20:23: note: candidate is:
14:13: note: virtual int Derived::f(int) const
14:13: note:   candidate expects 1 argument, 2 provided
Run Code Online (Sandbox Code Playgroud)

为什么是这样?是不是可以做这种超载?

Bat*_*eba 10

你需要写

class Derived : public Base {

    public:
        using Base::f;
        int f(int a) const { return a; }
};
Run Code Online (Sandbox Code Playgroud)

请注意using声明.这将基类版本带回范围.


Rei*_*ica 8

现在,我希望这两个函数具有相同的名称, f

你需要写

class Derived : public Base {

    public:
        using Base::f;
        int f(int a) const { return a; }
};
Run Code Online (Sandbox Code Playgroud)

请注意using声明.这将基类版本带回范围.[感谢@Bathsheba]

为什么是这样?是不是可以做这种超载?

不,由于[basic.scope.hiding3],原始问题中写的不可能:

在成员函数定义中,块作用域中名称的声明隐藏了具有相同名称的类成员的声明; 见[basic.scope.class].派生类中成员的声明隐藏了同名基类成员的声明; 见[class.member.lookup].

该子句涉及名称,而不是重载.因此,如果基类中存在其他重载并不重要,它们都共享相同的名称,根据上面的引用隐藏它们.

  • 请随意将我的答案复制到这个答案的顶部; 它会用它读得更好. (2认同)