我有一个具有相同名称的函数,但在基类和派生类中具有不同的签名。当我尝试在继承自派生的另一个类中使用基类的函数时,我收到一个错误。请参阅以下代码:
class A
{
public:
void foo(string s){};
};
class B : public A
{
public:
int foo(int i){};
};
class C : public B
{
public:
void bar()
{
string s;
foo(s);
}
};
我从gcc编译器收到以下错误:
In member function `void C::bar()': no matching function for call to `C::foo(std::string&)' candidates are: int B::foo(int)
如果我从类int foo(int i){};
中删除B
,或者如果我从foo1
重命名它,一切正常。
这有什么问题?
派生类中的函数不覆盖基类中的函数但具有相同的名称将隐藏基类中同名的其他函数。
通常认为在派生类中具有与低音类中的函数同名的函数是不好的做法,这些函数不打算覆盖基类函数,因为您所看到的通常不是理想的行为。通常最好给不同的功能赋予不同的名称。
如果需要调用基本函数,则需要使用A::foo(s)
来调整调用范围。请注意,这也会同时禁用A::foo(string)
的任何虚函数机制。
这是因为如果名称查找在您的某个基础中找到了名称,则会停止查找。它不会超越其他基础。 B中的函数隐藏了A中的函数。您必须在B的范围内重新声明A的函数,以便从B和C中可以看到这两个函数:
class A
{
public:
void foo(string s){};
};
class B : public A
{
public:
int foo(int i){};
using A::foo;
};
class C : public B
{
public:
void bar()
{
string s;
foo(s);
}
};
编辑:标准给出的真实描述是(从10.2 / 2):
以下步骤在类范围C中定义名称查找的结果。首先,考虑类中及其每个基类子对象中的名称的每个声明。如果A是B的基类子对象,则一个子对象B中的成员名称f隐藏子对象A中的成员名称f。任何如此隐藏的声明都将被排除在考虑范围之外。由using声明引入的每个声明都被认为是来自C的每个子对象,它包含由using-declaration指定的声明类型.96)如果生成的声明集不是所有来自相同类型的子对象,或者该集合具有非静态成员并且包括来自不同子对象的成员,存在歧义并且程序是不正确的。否则该集合是查找的结果。
它在另一个地方(就在它上面)有以下说法:
对于id-expression [类似“foo”],名称查找从此类的范围开始;对于qualified-id [类似“A :: foo”,A是嵌套名称说明符],名称查找从nested-name-specifier的范围开始。名称查找在访问控制之前进行(3.4,第11节)。
([...]由我提出)。请注意,这意味着即使您的B中的foo是私有的,仍然无法找到A中的foo(因为访问控制稍后会发生)。