ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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)

如果我从类 B 中删除 int foo(int i){};,或者如果我从 foo1 重命名它,一切正常。

这有什么问题?

技术上是 this question 的副本,但这个有更好的标题和答案。

J
Johannes Schaub - litb

这是因为如果在您的一个基地中找到名称,名称查找就会停止。它不会超越其他基地。 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 声明指定的声明。96) 如果声明的结果集不是全部来自相同类型的子对象,或者该集合具有非静态成员并包含来自不同子对象的成员,则存在歧义并且程序格式错误。否则,该集合是查找的结果。

它在另一个地方(就在它上面)有以下说法:

对于 id-expression [类似于 "foo"],名称查找从 this 的类范围开始;对于限定 ID [类似于“A::foo”,A 是嵌套名称说明符],名称查找在嵌套名称说明符的范围内开始。名称查找发生在访问控制之前(3.4,第 11 节)。

([...] 由我提出)。请注意,这意味着即使您在 B 中的 foo 是私有的,仍然无法找到 A 中的 foo(因为稍后会发生访问控制)。


litb,谢谢你的回答。但是当我尝试编译您的代码时,我得到:无法调整对 void A::foo(class basic_string<char,char_traits<char>,allocator<char> >)' in class B' 的访问,因为本地方法 `int B::foo(int)' 具有相同的名称。也许是因为我使用的是旧版本的 gcc
是的,绝对是编译器错误。旧的编译器曾经使用“A::foo;”而不是“使用 A::foo;”但前者在 C++ 中已被弃用。
C
CB Bailey

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

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

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


还阅读了 litdb 的回答:您可以通过 B 中的“使用 A::foo”子句“取消隐藏”基本函数。
没错,我只是在寻找可以在呼叫站点使用的解决方案,将基本层次结构视为固定的。
此声明的基础是什么,并附有建议:“通常认为在派生类中具有与 Bass 类中的函数同名的函数是不好的做法,这些函数并不打算将基类函数覆盖为您所看到的通常不是可取的行为。通常最好给不同的函数提供不同的名称“。如果他们在语义上做同样的事情怎么办?正如约翰内斯的回答所解释的那样,C++ 为您提供了由此引起的问题的解决方案。