重载虚函数集的部分继承
Posted
技术标签:
【中文标题】重载虚函数集的部分继承【英文标题】:partial inheritance of set of overloaded virtual functions 【发布时间】:2015-09-25 02:57:59 【问题描述】:我以为我了解继承、虚函数和函数重载,但我有一个案例,这些功能之间的相互作用让我难以理解。
假设我有一个包含重载虚函数的简单基类,以及从它派生的第二个类:
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 说“没有匹配的函数来调用 'd::f()';候选者是:virtual int d::f(int)”。 clang 说“函数调用的参数太少,预期为 1,有 0;你的意思是 'b::f'?”即使d
是从b
派生的,它有一个0 参数f()
方法,编译器会忽略它,并尝试调用d
的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;
但我的问题是,我违反了什么规则,该规则试图执行/保护/捍卫什么?我认为我在这里尝试做的正是我认为继承的那种事情。
【问题讨论】:
这个话题讨论的很好***.com/questions/1628768/… 【参考方案1】:这被称为名称隐藏。
在派生类中声明同名函数时,基类中的所有同名函数都将被隐藏。
为了获得对它们的无限制访问权限,请将using
声明添加到您的派生类中:
class d : public b
public:
using b::f;
virtual int f(int) return 3;
;
【讨论】:
标准里有吗? @OthmanBenchekroun [basic.scope.hiding]/1A name can be hidden by an explicit declaration of that same name in a nested declarative region or derived class.
@OthmanBenchekroun 同样在 13.2 声明匹配中,与史蒂夫给出的相同示例(或几乎如此)
谢谢!我现在看到我的问题是一个相当常见的问题,例如堆栈溢出 here 和 here 以及 C++ 常见问题列表 here。但我仍然想知道......为什么?只是为了让编译器更容易,还是这种继承被认为是个坏主意?
@SteveSummit 你可能可以找到一个更官方的来源,我没有详细考虑过它,但我想它可以通过继承功能来阻止你在脚上开枪您正在积极尝试阻止派生类。另外,如果没有该规则,您会怎么说“我不希望这个基类函数可见”?【参考方案2】:
除了@TartanLlama 的回答之外的一些解释:
当编译器必须解析对f
的调用时,它会按顺序执行三项主要操作:
名称查找。在执行任何其他操作之前,编译器会搜索一个范围,该范围至少具有一个名为 f
的实体并列出候选对象。在这种情况下,名称查找首先会在d
的范围内查找是否至少有一个名为f
的成员;如果没有,基类和封闭的命名空间
将依次考虑,一次一个,直到一个范围至少有一个
找到了候选人。但是,在这种情况下,编译器的第一个作用域
查找已经有一个名为f
的实体,然后名称查找停止。
重载分辨率。接下来,编译器执行重载决议来挑选 候选人列表中唯一的最佳匹配。在这种情况下,参数的计数不匹配,因此失败。
可访问性检查。最后,编译器执行可访问性检查以确定是否可以调用所选函数。
参考Name lookup
【讨论】:
以上是关于重载虚函数集的部分继承的主要内容,如果未能解决你的问题,请参考以下文章