c++ - 对如何覆盖虚函数的要求是否发生了变化?
问题描述
请看这个例子
#include <iostream>
class B{
public:
virtual void fun() &{ //#1
std::cout<<"base\n";
}
};
class A:public B{
public:
void fun(){ //#2
std::cout<<"override\n";
}
};
int main(){
A a;
B* ptr = &a;
ptr->fun();
}
GCCbase
在 Clang 提示错误诊断时打印。在当前草案中,相关规则是这样定义的:
[class.virtual#2]
如果在类 B 中声明了一个虚成员函数 F,并且在从 B 派生(直接或间接)的类 D 中,成员函数 G 的声明对应于 ([basic.scope.scope]) F 的声明,忽略尾随的要求子句,然后 G 覆盖 F。
同时,定义两个对应的声明的规则是这样定义的:
[basic.scope#scope-3]
如果两个声明(重新)引入相同的名称,都声明构造函数,或都声明析构函数,则两个声明对应,除非
- [...]
- each 声明一个函数或函数模板,除非
- 两者都声明具有相同参数类型列表的函数,等效 ([temp.over.link]) 尾随要求子句(如果有,除非 [temp.friend] 中指定),并且如果两者都是非静态成员, 相同的 cv-qualifiers (如果有的话) 和 ref-qualifiers (如果两者都有的话), 或者
在此示例中,#1
并且#2
具有相同的参数类型列表,#1
具有一个引用限定符而#2
没有,因此可以忽略后一个限制,因此,对于这两个声明,我们可以说它们是对应的。因此,#2
覆盖#1
声明为虚函数。因此,如果我们遵守当前的草案,我们可以说 GCC 和 Clang 的结果都是错误的。
但是,在c++20标准中,如何确定派生类中声明的声明覆盖基类中声明的虚函数的限制是:
[class.virtual#2]
如果虚成员函数 vf 在类 Base 和 Derived 类中声明,直接或间接从 Base 派生,则具有相同名称、参数类型列表 ([dcl.fct])、cv 限定的成员函数 vf , 和 ref-qualifier (或没有相同)作为 Base::vf 被声明,然后 Derived::vf 覆盖 Base::vf。
很明显,现在的规则已经改变了它原来的含义。这是新规则的缺陷吗?或者,只是为了改变需求而进行的人为设计?
解决方案
推荐阅读
- python - Tkinter Listbox:操纵行的显示(或显示一列但来自同一数据帧的另一列)
- javascript - Node.js 服务器请求对象在函数中定义时似乎没有被隔离
- c# - 截至今天,omnisharp 无法正常启动(无法从程序集中加载“CheckForDuplicateFrameworkReferences”任务 [...])
- javascript - 如何从 php 文件中的 javascript 文件调用函数
- list - 使用索引列表实现 map 函数
- mongodb - 事务将与 mongodb 聚合 $merge 一起使用吗?
- c++ - 使用函数、模板元编程或任何其他解决方案返回类型名
- opentext - Livelink - OpenText:调用 rmclassifications 以通过 API 更新状态
- jackson - WebFlux:如何反序列化控制器的接口参数?
- c# - 已达到最大池大小。Sql 服务器, c#