这个问题在这里已有答案:
使用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
为什么是这样?是不是可以做这种超载?
你需要写
class Derived : public Base {
public:
using Base::f;
int f(int a) const { return a; }
};
请注意using
声明。这将基类版本带回范围。
现在,我希望这两个函数具有相同的名称
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]。
该子句涉及名称,而不是重载。因此,如果基类中存在其他重载并不重要,它们都共享相同的名称,根据上面的引用隐藏它们。
您可以通过编写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.我也知道这个编译器很古老,但仅适用于关心的人;)
除了其他解决方案,如果您不想重新定义f
,您可以使用显式调用基类的f
int main() {
Derived obj;
cout << obj.f1(1) << endl;
cout << obj.Base::f2(1, 2) << endl;
}
您也可以将它们全部设为纯,然后在派生类中覆盖它们。您可以根据需要继续使用您的课程。