我有一个具有相同名称的函数,但在基类和派生类中具有不同的签名。当我尝试在继承自派生的另一个类中使用基类的函数时,我收到一个错误。请参阅以下代码:
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
重命名,则一切正常。
这有什么问题?
答案 0 :(得分:101)
这是因为如果在您的某个基础中找到名称,名称查找将停止。它不会超越其他基础。 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。首先,每个语句的声明 考虑类中的名称以及每个基类子对象中的名称。一个成员名称f在一个子 如果A是B的基类子对象,则对象B在子对象A中隐藏成员名称F.任何声明 如此隐藏的东西被排除在考虑之外。由a引入的每个声明 using-declaration被认为是来自C的每个子对象,包含声明的类型 - 使用声明指定的内容.96)如果生成的声明集不是全部来自子对象 相同类型的集合,或者集合具有非静态成员,并且包括来自不同子对象的成员 模棱两可,程序结构不合理。否则该集合是查找的结果。
在另一个地方(就在它上面)有以下说法:
对于id-expression [类似“foo”],名称查找从此类的范围开始;对于qualified-id [类似“A :: foo”,A是嵌套名称说明符],名称查找从nested-name-specifier的范围开始。名称查找在访问控制(3.4,第11节)之前进行。
([...]由我提出)。请注意,即使您的B中的foo是私有的,也仍然无法找到A中的foo(因为访问控制稍后会发生)。
答案 1 :(得分:71)
派生类中不覆盖基类中的函数但具有相同名称的函数将隐藏基类中同名的其他函数。
通常认为在派生类中具有与低音类中的函数同名的函数并且不打算覆盖基类函数通常被认为是不好的做法,因为您所看到的通常不是理想的行为。通常最好给不同的功能赋予不同的名称。
如果您需要调用基本功能,则需要使用A::foo(s)
来调整呼叫范围。请注意,这也会同时禁用A::foo(string)
的任何虚函数机制。