为什么派生类中的重载函数隐藏了基类的其他重载?
考虑下面的代码:
#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 test test.cpp:在函数`int main()'中: test.cpp:31:错误:没有匹配的函数调用“Derived :: gogo(int)” test.cpp:21:注意:候选人是:virtual void Derived :: gogo(int *) test.cpp:33:2:警告:文件末尾没有换行符 >退出代码:1
在这里,Derived类的函数将基类中所有具有相同名称(不是签名)的函数进行分割。 不知何故,C ++的这种行为看起来不好。 不是多态的。
从你的问题的措辞来看(你用“隐藏”一词),你已经知道这里发生了什么事情。 这种现象被称为“名称隐藏”。 出于某种原因,每当有人提出一个关于为什么隐藏名字的问题时,回应的人都会说这叫做“名称隐藏”并解释它是如何工作的(你可能已经知道了),或者说明如何覆盖它(你从来没有问过),但似乎没有人关心实际的“为什么”的问题。
这个决定是隐藏名称的原因 ,也就是为什么它实际上被devise成C ++,是为了避免某些违反直觉的,不可预见的和有潜在危险的行为,如果inheritance的重载函数被允许与当前的给定类中的重载。 您可能知道,在C ++重载parsing中,通过从候选集合中select最佳函数来工作。 这是通过将参数types与参数types进行匹配来完成的。 匹配规则有时可能会变得复杂,而且往往导致可能被无准备的用户认为是不合逻辑的结果。 向一组先前存在的函数添加新的函数可能会导致重载parsing结果发生相当大的转变。
例如,假设基类B
有一个成员函数foo
,它接受一个void *
types的参数,所有对foo(NULL)
调用都被parsing为B::foo(void *)
。 假设没有名称隐藏,这个B::foo(void *)
在许多不同的从B
类降序的类中是可见的。 然而,让我们假设在B
类的一些[indirect,remote]子孙D
中定义了一个函数foo(int)
。 现在,没有名称隐藏D
有foo(void *)
和foo(int)
可见并参与重载parsing。 如果通过typesD
的对象进行调用,那么哪个函数会调用foo(NULL)
? 它们将parsing为D::foo(int)
,因为int
比任何指针types都更好地匹配整型零(即NULL
)。 所以,在整个层次调用foo(NULL)
parsing为一个函数,而在D
(和下)他们突然解决到另一个。
这种行为在devise语言时被认为是不可取的。 作为一个更好的方法,决定遵循“名称隐藏”规范,这意味着每个类对于其声明的每个方法名称都以“干净的表格”开始。 为了覆盖这个行为,用户需要一个明确的操作:最初是对inheritance的方法的重新声明(现在已经被弃用),现在明确地使用using声明。
正如你在原来的文章中正确的观察到的那样(我指的是“Not polymorphic”的评论),这种行为可能被视为违反了类之间的IS-A关系。 这是真的,但显然当时的决定,隐藏的名字将被certificate是一个较小的邪恶。
名称parsing规则表示名称查找停止在find匹配名称的第一个作用域中。 在这一点上,重载parsing规则开始寻找可用函数的最佳匹配。
在这种情况下, gogo(int*)
在Derived类作用域中find(单独),并且由于没有从int到int *的标准转换,查找失败。
解决方法是通过Derived类中的using声明来引入Base声明:
using Base::gogo;
…将允许名称查找规则查找所有候选人,因此重载解决scheme将按照您的预期进行。
这是“按devise”。 在这种types的方法的C ++重载分辨率工作如下。
- 从引用types开始,然后转到基types,find第一个types,它有一个名为“gogo”的方法
- 考虑只有名为“gogo”的方法find匹配的重载
由于Derived没有名为“gogo”的匹配函数,所以重载parsing失败。