为什么在派生类中重写的函数隐藏了基类的其他重载? [英] Why does an overridden function in the derived class hide other overloads of the base class?

查看:105
本文介绍了为什么在派生类中重写的函数隐藏了基类的其他重载?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑代码:

#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: 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

这里,Derived类的函数是eclipsing在基类中具有相同名称(不是签名)的所有函数。不知怎的,这种C ++的行为看起来不行。不是多态性。

Here, the Derived class's function is eclipsing all functions of same name (not signature) in the base class. Somehow, this behaviour of C++ does not look OK. Not polymorphic.

推荐答案

根据你的问题的措辞(你使用hide在这里。这种现象称为名称隐藏。由于某种原因,每次有人询问有关为什么名称隐藏的问题时,响应的人都会说这称为名称隐藏并解释其工作原理(您可能已经知道),或解释如何覆盖它(你从来没有问过),但没有人似乎关心实际的为什么的问题。

Judging by the wording of your question (you used the word "hide"), you already know what is going on here. The phenomenon is called "name hiding". For some reason, every time someone asks a question about why name hiding happens, people who respond either say that this called "name hiding" and explain how it works (which you probably already know), or explain how to override it (which you never asked about), but nobody seems to care to address the actual "why" question.

这个决定, ,即为什么它实际上被设计为C ++,是为了避免某些违反直觉,不可预见和潜在危险的行为,如果允许继承的重载函数集合与当前的重载集合给定类。你可能知道在C ++重载分辨率工作通过从候选集合中选择最好的函数。这通过将参数的类型与参数的类型相匹配来完成。匹配规则有时可能是复杂的,并且经常导致可能被无准备的用户感觉为不合逻辑的结果。向一组以前存在的函数添加新函数可能会导致重载解析结果发生相当剧烈的变化。

The decision, the rationale behind the name hiding, i.e. why it actually was designed into C++, is to avoid certain counterintuitive, unforeseen and potentially dangerous behavior that might take place if the inherited set of overloaded functions were allowed to mix with the current set of overloads in the given class. You probably know that in C++ overload resolution works by choosing the best function from the set of candidates. This is done by matching the types of arguments to the types of parameters. The matching rules could be complicated at times, and often lead to results that might be perceived as illogical by an unprepared user. Adding new functions to a set of previously existing ones might result in a rather drastic shift in overload resolution results.

例如,假设基类 B 有一个成员函数 foo ,它接受类型 void * 的参数,所有对 foo(NULL)的调用都解析为 B :: foo(void *)。让我们说没有名字隐藏,这个 B :: foo(void *)在从 B 。但是,让我们说在 B 类的一些[间接,远程]后代 D 定义了foo(int)。现在,没有名称隐藏 D 同时具有 foo(void *) foo 可见和参与重载分辨率。哪个函数将调用 foo(NULL)解析为,如果通过类型 D 的对象做?它们将解析为 D :: foo(int),因为 int code> NULL )。所以,在整个层次调用 foo(NULL)解析一个函数,而在 D 突然解决了另一个。

For example, let's say the base class B has a member function foo that takes a parameter of type void *, and all calls to foo(NULL) are resolved to B::foo(void *). Let's say there's no name hiding and this B::foo(void *) is visible in many different classes descending from B. However, let's say in some [indirect, remote] descendant D of class B a function foo(int) is defined. Now, without name hiding D has both foo(void *) and foo(int) visible and participating in overload resolution. Which function will the calls to foo(NULL) resolve to, if made through an object of type D? They will resolve to D::foo(int), since int is a better match for integral zero (i.e. NULL) than any pointer type. So, throughout the hierarchy calls to foo(NULL) resolve to one function, while in D (and under) they suddenly resolve to another.

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

This behavior was deemed undesirable when the language was designed. As a better approach, it was decided to follow the "name hiding" specification, meaning that each class starts with a "clean sheet" with respect to each method name it declares. In order to override this behavior, an explicit action is required from the user: originally a redeclaration of inherited method(s) (currently deprecated), now an explicit use of using-declaration.

正如你在原始帖子中正确观察到的(我指的是非多态性注释),这种行为可能被视为违反类之间的IS-A关系。这是真的,但显然当时决定,在最后的名字隐藏将证明是一个较小的邪恶。

As you correctly observed in your original post (I'm referring to the "Not polymorphic" remark), this behavior might be seen as a violation of IS-A relationsip between the classes. This is true, but apparently back then it was decided that in the end name hiding would prove to be a lesser evil.

这篇关于为什么在派生类中重写的函数隐藏了基类的其他重载?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆