- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
考虑代码:
#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)
。现在,没有名称隐藏 D
有 foo(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/
假设我有一个类,我在其中重载了运算符 == : Class A { ... public: bool operator== (const A &rhs) const; ... };
我知道你不应该使用 std::find(some_map.begin(), some_map.end()) 或 std::lower_bound,因为它会采用线性时间而不是 some_map.lowe
我正在尝试在 Haskell 中定义 Vector3 数据类型,并允许在其上使用 (+) 运算符。我尝试了以下方法: data Vector3 = Vector3 Double Double Doub
我已经为我的类图将运算符重载为“-”。它的用途并不完全直观(糟糕的编码 - 我知道)但是如果我做 graph3 = graph2-graph1 那么图 3 是应该只接收图 2 和图 1 中的那些顶点。
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: Operator overloading 我想重载 以按字母顺序排列字符串,但我不确定该怎么做。 如何再次
下面的代码给我一个编译错误。谁能告诉我为什么? class mytype { public: int value; mytype(int a) { value = a;
这有什么问题吗? class Vec2 attr_accessor :x, :y # ... def += (v) @x += v.x @y += v.y retu
是否可以重载 [] 运算符两次?允许这样的事情:function[3][3](就像在二维数组中一样)。 如果可能的话,我想看看一些示例代码。 最佳答案 您可以重载 operator[] 以返回一个对象
我的团队目前正在与 Lua 合作,创建一个 android 游戏。我们遇到的一件事是表面上无法创建重载构造函数。 我习惯于使用默认值设置一个对象,然后在需要时使其过载。 前任: apples() {
我有一个网页,在某个时候显示一个导航栏,它只不过是一个 a 元素的列表 (ul)。所述 a 元素的大多数样式规则都是通用的。唯一应该改变的部分是要显示的图像,可以从列表中每个 li 元素的 id 标签
我对使用/重载“范围步长”运算符(.. ..)很感兴趣,但我终其一生都无法了解如何使用它。 在文档中它说 // Usage: start .. step .. finish 但是在 F# shell
Java 11(可能无关紧要): public static String toString(Object obj) { return ReflectionToStringBuilder.to
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
我无法理解以下代码(针对行号进行注释) class Base { void m1(Object o) { } void m2(String o) { } } publi
我有以下代码片段: #include using namespace std; struct Integer{ int x; Integer(const int val) : x(v
class myclass{ //definitions here }; myclass e; int myarray[10]; /* Do something... */ e = myarray;
为什么不能将下标运算符(operator [])作为 friend 函数重载? 最佳答案 正如Bjarne Stroustrup在D&E book中所说: However, even in the o
我有以下代码片段: #include using namespace std; struct Integer{ int x; Integer(const int val) : x(v
因此,我有一个问题是我最近尝试重载 namespace Eng { /** * A structure to represent pixels */ typedef
如何重载onResume()以正确的方式工作?我想从 activity 返回到 MainActivity ,我希望在其中具有与应用程序启动后相同的状态。我想使用 recreate() 但它循环了或者类
我是一名优秀的程序员,十分优秀!