关于c ++:派生类中具有相同名称但签名不同的函数

Function with same name but different signature in derived class

我有一个同名的函数,但在基类和派生类中具有不同的签名。当我试图在从派生类继承的另一个类中使用基类的函数时,我收到一个错误。请参见以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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编译器收到以下错误:

1
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中重命名,那么一切都会正常工作。

这有什么问题?


这是因为如果名称查找在您的一个基中找到一个名称,它就会停止。它不会在其他基地遥遥领先。B中的函数隐藏A中的函数。您必须在B的范围内重新声明A的函数,以便从B和C中可以看到这两个函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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开始):

The following steps define the result of name lookup in a class scope, C. First, every declaration for the
name in the class and in each of its base class sub-objects is considered. A member name f in one sub-
object B hides a member name f in a sub-object A if A is a base class sub-object of B. Any declarations
that are so hidden are eliminated from consideration. Each of these declarations that was introduced by a
using-declaration is considered to be from each sub-object of C that is of the type containing the declara-
tion designated by the using-declaration.96) If the resulting set of declarations are not all from sub-objects
of the same type, or the set has a nonstatic member and includes members from distinct sub-objects, there is
an ambiguity and the program is ill-formed. Otherwise that set is the result of the lookup.

在另一个地方(就在上面),它可以说:

For an id-expression [something like"foo"], name lookup begins in the class scope of this; for a qualified-id [something like"A::foo", A is a nested-name-specifier], name lookup begins in the scope of the nested-name-specifier. Name lookup takes place before access control (3.4, clause 11).

([…]我说)。注意,这意味着即使您在B中的foo是私有的,在A中的foo仍然找不到(因为访问控制稍后发生)。


派生类中不重写基类中的函数但具有相同名称的函数将隐藏基类中具有相同名称的其他函数。

通常认为,在派生类中具有与bass类中的函数同名的函数是不好的做法,因为这些派生类并不打算重写基类函数,因为您看到的通常是不可取的行为。通常最好给不同的函数取不同的名称。

如果需要调用基函数,则需要使用A::foo(s)来确定调用的范围。注意,这也会同时禁用A::foo(string)的任何虚拟功能机制。