我认为我理解了继承,虚函数和函数重载,但我有一个案例,其中有关于这些特征之间的相互作用的事情让我望而却步。
假设我有一个包含重载虚函数的简单基类,以及从中派生的第二个类:
class b {
public:
virtual int f() { return 1; }
virtual int f(int) { return 2; }
};
class d : public b {
public:
virtual int f(int) { return 3; }
};
请注意,派生类d
仅覆盖其中一个重载的虚函数。
我可以实例化一个类d
的对象并在其上调用f(int)
,没问题:
d x;
std::cout << x.f(0) << std::endl;
但是当我尝试调用0参数函数时:
std::cout << x.f() << std::endl;
失败了! gcc说&#34;没有匹配函数来调用&#39; d :: f()&#39 ;;候选者是:virtual int d :: f(int)&#34;。 clang说&#34;函数调用的参数太少,预期为1,有0;你的意思是&#39; b :: f&#39;?&#34;尽管d
派生自具有0参数b
方法的f()
,但编译器忽略了这一点,并试图调用d
&#39; s 1-改为参数方法。
我可以通过重复派生类中的0参数函数的定义来解决这个问题:
class d : public b {
public:
virtual int f() { return 1; }
virtual int f(int) { return 3; }
};
或者,正如clang的错误消息所示,我可以使用一种我从未猜到的愚蠢消歧语法:
std::cout << x.b::f() << std::endl;
但我的问题是,我打破了什么规则,试图强制执行/保护/捍卫的规则是什么?我以为我试图在这里做的就是我认为继承的那种东西。
答案 0 :(得分:7)
这称为名称隐藏。
在派生类中声明具有相同名称的函数时,将隐藏基础中具有相同名称的所有函数。
为了获得对它们的无限制访问权限,请在派生类中添加using
声明:
class d : public b {
public:
using b::f;
virtual int f(int) { return 3; }
};
答案 1 :(得分:2)
除了@ TartanLlama的答案之外还有一些解释:
当编译器必须解析对Private Sub Worksheet_Change(ByVal Target As Range)
Set Rng = Range("D11:D88")
If Target.Count = 1 Then
If Not Intersect(Target, Rng) Is Nothing Then
Application.EnableEvents = False
Target(1).Offset(0, 1).Value = Environ$("username")
Target(1).Offset(0, 2).Value = Date
Target(1).Offset(0, 3).Value = Time
Application.EnableEvents = True
End If
End If
End Sub
的调用时,它按顺序执行三项主要操作:
名称查找。在执行任何其他操作之前,编译器会搜索至少包含一个名为f
的实体的范围,并生成候选列表。在这种情况下,名称查找首先查看f
的范围,以查看是否至少有一个名为d
的成员;如果没有,基类和封闭的命名空间
将依次考虑,一次一个,直到具有至少一个的范围
候选人被发现。但在这种情况下,编译器的第一个范围
查看已经有一个名为f
的实体,然后名称查找停止。
重载分辨率。接下来,编译器执行重载决策以进行选择 候选人名单中唯一的最佳匹配。在这种情况下,参数的计数不匹配,因此失败。
辅助功能检查。最后,编译器执行可访问性检查以确定是否可以调用所选函数。