gpt4 book ai didi

c++ - 为什么派生类中的重写函数会隐藏基类的其他重载?

转载 作者:太空宇宙 更新时间:2023-11-04 13:48:11 25 4
gpt4 key购买 nike

考虑代码:

#include <stdio.h>

class Base {
public:
virtual void gogo(int a){
printf(" Base :: gogo (int) \n");
};

virtual void gogo(int* a){
printf(" Base :: gogo (int*) \n");
};
};

class Derived : public Base{
public:
virtual void gogo(int* a){
printf(" Derived :: gogo (int*) \n");
};
};

int main(){
Derived obj;
obj.gogo(7);
}

遇到这个错误:

>g++ -pedantic -Os test.cpp -o testtest.cpp: In function `int main()':test.cpp:31: error: no matching function for call to `Derived::gogo(int)'test.cpp:21: note: candidates are: virtual void Derived::gogo(int*) test.cpp:33:2: warning: no newline at end of file>Exit code: 1

在这里,派生类的函数使基类中所有同名(不是签名)的函数黯然失色。不知何故,C++ 的这种行为看起来并不正常。不是多态的。

最佳答案

从你问题的措辞来看(你使用了“隐藏”这个词),你已经知道这里发生了什么。这种现象称为“名称隐藏”。出于某种原因,每次有人问为什么会隐藏名字时,回答的人要么说这叫做“名字隐藏”并解释它是如何工作的(你可能已经知道),要么解释如何覆盖它(你从未问过),但似乎没有人关心解决实际的“为什么”问题。

这个决定,名称隐藏背后的基本原理,即 为什么 它实际上被设计到 C++ 中,是为了避免如果继承集可能发生的某些反直觉的、不可预见的和潜在的危险行为允许重载函数与给定类中的当前重载集混合。您可能知道,在 C++ 中,重载解析通过从候选集合中选择最佳函数来工作。这是通过将参数类型与参数类型相匹配来完成的。匹配规则有时可能很复杂,并且经常导致可能被没有准备的用户认为不合逻辑的结果。向一组先前存在的函数中添加新函数可能会导致重载解析结果发生相当大的变化。

例如,假设基类 B 有一个成员函数 foo,它接受类型为 void * 的参数,所有调用foo(NULL) 被解析为 B::foo(void *)。假设没有名称隐藏,并且此 B::foo(void *)B 的许多不同类中可见。但是,假设在类 B 的某些 [间接,远程] 后代 D 中定义了一个函数 foo(int)。现在,没有名称隐藏 Dfoo(void *)foo(int) 可见并参与重载决议。如果通过 D 类型的对象调用,对 foo(NULL) 的调用将解析为哪个函数?它们将解析为 D::foo(int),因为 int 比任何指针类型都更适合整数零(即 NULL) .因此,在整个层次结构中,对 foo(NULL) 的调用解析为一个函数,而在 D(及以下)中,它们突然解析为另一个函数。

The Design and Evolution of C++ 中给出了另一个示例,第 77 页:

class Base {
int x;
public:
virtual void copy(Base* p) { x = p-> x; }
};

class Derived : public Base{
int xx;
public:
virtual void copy(Derived* p) { xx = p->xx; Base::copy(p); }
};

void f(Base a, Derived b)
{
a.copy(&b); // ok: copy Base part of b
b.copy(&a); // error: copy(Base*) is hidden by copy(Derived*)
}

如果没有这个规则,b 的状态将被部分更新,导致切片。

在设计语言时,这种行为被认为是不可取的。作为一种更好的方法,决定遵循“名称隐藏”规范,这意味着每个类都以关于它声明的每个方法名称的“干净表”开始。为了覆盖此行为,需要用户执行明确的操作:最初是重新声明继承的方法(目前已弃用),现在是明确使用 using-declaration。

正如您在原始帖子中正确观察到的(我指的是“非多态”评论),此行为可能被视为违反了类之间的 IS-A 关系。这是事实,但显然当时决定最终证明隐藏姓名是一种较小的邪恶。

关于c++ - 为什么派生类中的重写函数会隐藏基类的其他重载?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24804734/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com