在派生类中具有相同名称但不同签名的函数

时间:2021-07-28 23:58:43

I have a function with the same name, but with different signature in a base and derived classes. When I am trying to use the base class's function in another class that inherits from the derived, I receive an error. See the following code:

我有一个名称相同但在基类和派生类中有不同签名的函数。当我试图在继承自派生类的另一个类中使用基类的函数时,我收到一个错误。看下面的代码:

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);
    }
};

I receive the following error from the gcc compiler:

我从gcc编译器收到以下错误:

In member function `void C::bar()': no matching function for call to `C::foo(std::string&)' candidates are: int B::foo(int)

If I remove int foo(int i){}; from class B, or if I rename it from foo1, everything works fine.

如果我删除int foo(int I){};从B类,或者如果我从foo1重命名,一切都没问题。

What's the problem with this?

这有什么问题?

2 个解决方案

#1


65  

Functions in derived classes which don't override functions in base classes but which have the same name will hide other functions of the same name in the base class.

派生类中的函数,它不覆盖基类中的函数,但具有相同名称的函数将在基类中隐藏相同名称的其他函数。

It is generally considered bad practice to have have functions in derived classes which have the same name as functions in the bass class which aren't intended to override the base class functions as what you are seeing is not usually desirable behaviour. It is usually preferable to give different functions different names.

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

If you need to call the base function you will need to scope the call by using A::foo(s). Note that this would also disable any virtual function mechanism for A::foo(string) at the same time.

如果需要调用基函数,则需要使用A::foo(s)对调用进行限定。注意,这还将禁用一个::foo(string)的任何虚函数机制。

#2


92  

It is because name lookup stops if it finds a name in one of your bases. It won't look beyond in other bases. The function in B shadows the function in A. You have to re-declare the function of A in the scope of B, so that both functions are visible from within B and C:

这是因为名称查找在您的一个碱基中找到一个名称时停止。它不会超越其他基地。B中的函数将A中的函数投影到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);
    }
};

Edit: The real description the Standard gives is (from 10.2/2):

编辑:标准给出的真实描述为(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.

下面的步骤定义类作用域c中的名称查找结果。首先,要考虑类中的名称及其每个基类子对象的每个声明。如果A是B的基类子对象,那么一个子对象B中的成员名f在子对象A中隐藏了一个成员名f。这些声明引入的using声明被认为是来自每个对象的C类型包含declara using-declaration.96)如果指定的,由此产生的声明并非都是相同类型的子对象,或一组有一个非静态的成员,包括成员来自不同的子对象,有一个歧义和程序不规范的。否则,该集合就是查找的结果。

It has the following to say in another place (just above it):

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

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).

对于一个id-expression(类似于“foo”),名称查找从类范围开始;对于一个限定id(比如“a::foo”,a是一个嵌套名称说明符),名称查找从嵌套名称说明符的范围开始。在访问控制(3.4,第11条)之前进行名称查找。

([...] put by me). Note that means that even if your foo in B is private, the foo in A will still not be found (because access control happens later).

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

#1


65  

Functions in derived classes which don't override functions in base classes but which have the same name will hide other functions of the same name in the base class.

派生类中的函数,它不覆盖基类中的函数,但具有相同名称的函数将在基类中隐藏相同名称的其他函数。

It is generally considered bad practice to have have functions in derived classes which have the same name as functions in the bass class which aren't intended to override the base class functions as what you are seeing is not usually desirable behaviour. It is usually preferable to give different functions different names.

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

If you need to call the base function you will need to scope the call by using A::foo(s). Note that this would also disable any virtual function mechanism for A::foo(string) at the same time.

如果需要调用基函数,则需要使用A::foo(s)对调用进行限定。注意,这还将禁用一个::foo(string)的任何虚函数机制。

#2


92  

It is because name lookup stops if it finds a name in one of your bases. It won't look beyond in other bases. The function in B shadows the function in A. You have to re-declare the function of A in the scope of B, so that both functions are visible from within B and C:

这是因为名称查找在您的一个碱基中找到一个名称时停止。它不会超越其他基地。B中的函数将A中的函数投影到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);
    }
};

Edit: The real description the Standard gives is (from 10.2/2):

编辑:标准给出的真实描述为(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.

下面的步骤定义类作用域c中的名称查找结果。首先,要考虑类中的名称及其每个基类子对象的每个声明。如果A是B的基类子对象,那么一个子对象B中的成员名f在子对象A中隐藏了一个成员名f。这些声明引入的using声明被认为是来自每个对象的C类型包含declara using-declaration.96)如果指定的,由此产生的声明并非都是相同类型的子对象,或一组有一个非静态的成员,包括成员来自不同的子对象,有一个歧义和程序不规范的。否则,该集合就是查找的结果。

It has the following to say in another place (just above it):

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

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).

对于一个id-expression(类似于“foo”),名称查找从类范围开始;对于一个限定id(比如“a::foo”,a是一个嵌套名称说明符),名称查找从嵌套名称说明符的范围开始。在访问控制(3.4,第11条)之前进行名称查找。

([...] put by me). Note that means that even if your foo in B is private, the foo in A will still not be found (because access control happens later).

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