在派生类中找不到同名但签名不同的函数

Function with same name but different signature in derived class not found

提问人:Igor 提问时间:1/4/2009 最后编辑:ks1322Igor 更新时间:2/21/2023 访问量:50115

问:

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

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

这是怎么回事?

C 函数 继承查找 C++-FAQ

评论

1赞 Troubadour 9/2/2011
从技术上讲,这个问题是重复的,但这个问题有更好的标题和答案。

答:

115赞 Johannes Schaub - litb 1/4/2009 #1

这是因为如果名称查找在您的一个基地中找到名称,它就会停止。它不会超越其他基地。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。任何声明 如此隐藏的东西被排除在考虑之外。这些声明中的每一个都是由 using-declaration 被认为是来自 C 的每个子对象,该子对象属于包含声明的类型 96) 如果生成的声明集并非全部来自子对象 相同类型的,或者集合具有非静态成员并包含来自不同子对象的成员,则有 模棱两可,程序格式不正确。否则,该集是查找的结果。

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

对于 id-expression [类似 “foo”],名称查找从 this 的类范围开始;对于 qualified-id [类似于 “A::foo”,A 是嵌套名称说明符],名称查找在嵌套名称说明符的作用域中开始。名称查找在访问控制之前进行(3.4,第 11 条)。

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

评论

0赞 Igor 1/5/2009
litb,谢谢你的回答。但是当我尝试编译您的代码时,我得到:由于同名的本地方法“int B::foo(int)”,无法调整对类 B 的访问。也许是因为我使用了旧版本的 gccvoid A::foo(class basic_string<char,char_traits<char>,allocator<char> >)' in
1赞 Johannes Schaub - litb 1/5/2009
是的,绝对是编译器错误。旧的编译器曾经使用“A::foo;”而不是“using A::foo;”,但前者在C++中被弃用。
88赞 CB Bailey 1/4/2009 #2

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

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

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

评论

14赞 xtofl 1/5/2009
另请阅读 litdb 的回答:您可以通过 B 中的“using A::foo”子句来“取消隐藏”基本函数。
0赞 CB Bailey 1/5/2009
没错,我只是在寻找一个可以在呼叫站点使用的解决方案,将基本层次结构视为固定的。
2赞 Nawaz 4/13/2018
这种说法的依据是什么,然后是建议:“在派生类中具有与 bass 类中的函数同名的函数通常被认为是不好的做法,这些函数并不打算覆盖基类函数,因为你所看到的通常不是理想的行为。通常最好给不同的函数起不同的名称”。如果他们在语义上做同样的事情呢?C++ 为您提供了由此引起的问题的解决方案,正如 Johannes 的回答所解释的那样。
0赞 MTV 2/15/2023
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.同名签名?我有点困惑,因为我发现有几篇文章认为这是 C++ 的方法覆盖版本(例如,C++ 中的 g4g 函数覆盖