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

问题描述 投票:10回答:5

使用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;
}

结果是

1
3

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

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

但是,如果我这样做(只需将f1和f2重命名为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;
}

我收到以下错误:

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

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

c++
5个回答
10
投票

你需要写

class Derived : public Base {

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

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


8
投票

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

你需要写

class Derived : public Base {

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

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

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

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

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

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


1
投票

您可以通过编写using Base::f;将Base的所有定义拉入范围,或者您可以为这样的某些版本的f这样写:int f(int a, int b) const override {return Base::f(a,b);}

class Derived : public Base {

public:
    int f(int a) const { return a; }
    int f(int a, int b) const override {return Base::f(a,b);} 
};

使用的版本已在此answer中提及:

class Derived : public Base {

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

注意:我知道第二个版本不适用于MSVC 2010.我也知道这个编译器很古老,但仅适用于关心的人;)


0
投票

除了其他解决方案,如果您不想重新定义f,您可以使用显式调用基类的f

int main() {
    Derived obj;
    cout << obj.f1(1) << endl;
    cout << obj.Base::f2(1, 2) << endl;
}

-2
投票

您也可以将它们全部设为纯,然后在派生类中覆盖它们。您可以根据需要继续使用您的课程。

© www.soinside.com 2019 - 2024. All rights reserved.