Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/reporting-services/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么派生类中的重写函数隐藏基类的其他重载?_C++_Polymorphism_Overriding - Fatal编程技术网

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

C++ 为什么派生类中的重写函数隐藏基类的其他重载?,c++,polymorphism,overriding,C++,Polymorphism,Overriding,以代码为例: #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{ p

以代码为例:

#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);
}
#包括
阶级基础{
公众:
虚拟虚空果戈(INTA){
printf(“Base::gogo(int)\n”);
};
虚空果戈(int*a){
printf(“Base::gogo(int*)\n”);
};
};
派生类:公共基{
公众:
虚空果戈(int*a){
printf(“派生::gogo(int*)\n”);
};
};
int main(){
派生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 >g++-pedantic-Os test.cpp-o test test.cpp:在函数“int main()”中: test.cpp:31:错误:调用“派生::gogo(int)”时没有匹配的函数 test.cpp:21:注:候选项为:虚拟空派生::gogo(int*) test.cpp:33:2:警告:文件末尾没有换行符 >退出代码:1 在这里,派生类的函数掩盖了基类中所有同名(非签名)的函数。不知怎么说,C++的这种行为看起来不太好。不是多态的。

这是“设计的”。在C++中,这种方法的过载解决方案的工作原理如下:
  • 从引用的类型开始,然后转到基类型,找到第一个具有名为“gogo”的方法的类型
  • 仅考虑该类型上名为“gogo”的方法,才能找到匹配的重载
由于派生函数没有名为“gogo”的匹配函数,因此重载解析失败

这是“设计”。在C++中,这种方法的过载解决方案的工作原理如下:
  • 从引用的类型开始,然后转到基类型,找到第一个具有名为“gogo”的方法的类型
  • 仅考虑该类型上名为“gogo”的方法,才能找到匹配的重载

由于派生函数没有名为“gogo”的匹配函数,因此重载解析失败

名称解析规则规定,名称查找在找到匹配名称的第一个范围内停止。在这一点上,重载解析规则开始寻找可用函数的最佳匹配

在这种情况下,在派生类作用域中(单独)找到了
gogo(int*)
,并且由于没有从int到int*的标准转换,因此查找失败

解决方案是通过派生类中的using声明引入基声明:

using Base::gogo;

…将允许名称查找规则查找所有候选名称,因此重载解析将按预期进行。

名称解析规则表示名称查找将在找到匹配名称的第一个作用域中停止。在这一点上,重载解析规则开始寻找可用函数的最佳匹配

在这种情况下,在派生类作用域中(单独)找到了
gogo(int*)
,并且由于没有从int到int*的标准转换,因此查找失败

解决方案是通过派生类中的using声明引入基声明:

using Base::gogo;

…将允许名称查找规则查找所有候选名称,因此过载解决将按照您的预期进行。

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

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

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

另一个例子是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的状态将部分更新,从而导致切片

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