覆盖非const虚拟方法是否隐藏了const超载?
-
08-10-2019 - |
题
考虑:
#include <iostream>
using namespace std;
struct A {
virtual void f() { cout << "A::f" << endl; }
virtual void f() const { cout << "A::f const" << endl; }
};
struct B : public A {};
struct C : public A {
virtual void f() { cout << "C::f" << endl; }
};
int main()
{
const B b;
b.f(); // prints "A::f const"
const C c;
c.f();
// Compile-time error: passing ‘const C’ as ‘this’ argument of
// ‘virtual void C::f()’ discards qualifiers
}
(我正在使用GCC。)
因此,似乎F()的const版本隐藏在C中。这对我来说很有意义,但是标准是否要求它?
解决方案
我会(再次)链接这个很棒的 文章 :
首先,[编译器]在直接范围中查看,在这种情况下为C类的范围,并列出所有可以找到的功能的列表参数)。 只有当它不这样做时,然后继续“向外”进入下一个封闭范围 [...]
是的, const
版本的 f
被隐藏了,这是完全正常的。如Simone指出的那样,您可以使用 using
带来的声明 A::f
在 C
范围。
其他提示
是的。您可以写:
struct C : public A {
virtual void f() { cout << "C::f" << endl; }
using A::f;
};
使您的代码编译:
int main()
{
const B b;
b.f(); // prints "A::f const"
const C c;
c.f(); // prints "A::f const"
}
有关更多信息,您可以参考2010 C ++草稿文档(您可以找到它 这里)第10.2章(3-4)。
隐藏基本成员的不是虚拟性或构造(或缺乏构造),任何派生的方法都隐藏了同名的基本方法。这样做是为了改善脆弱的基类问题。
想象一下您的代码工作(可能是多年),如下所示,删除了非相关零件:
struct Base {
};
struct Derived : Base {
void f(double);
}
void g(Derived &d) {
d.f(42);
}
然后,您需要修改基础以包含一种完全不同的方法,但是,由于某种原因,您想将其命名为“ f”:
struct Base {
void f(int);
};
没有这个规则, 每一个 需要手动评估使用派生的调用F-如果基本在给其他人的库中,您甚至可能无法访问其他用途!面对用户定义(隐式)转换,情况变得更糟。
取而代之的是,决定要求派生的类以明确说明他们想通过使用声明从基础中导入给定名称。这个规则可能令人惊讶,我不确定这对今天的语言是一个净收益,但是他们没有问我 - 当时,我可能只能用两个音节的单词回答他们。 :)
插入 using B::f;
struct C : public A {
using A::f;
virtual void f() { cout << "C::f" << endl; }
};
C ++标准2003。13.2P.1:
同一名称的两个函数声明,如果它们在同一范围中并且具有等效的参数声明(13.1),则指的是相同的函数。派生类的功能成员 不是 与基类中同名的函数成员相同的范围。
因此 C::f
隐藏着所有 A::f
.