重写非常量虚拟方法是否会隐藏常量重载?

发布于 2024-10-01 22:42:02 字数 629 浏览 1 评论 0原文

考虑一下:(

#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 中。这对我来说很有意义,但它是标准强制要求的吗?

Consider:

#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
}

(I'm using GCC.)

So it seems that the const version of f() gets hidden in C. This makes a lot of sense to me, but is it mandated by the standard?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

煮茶煮酒煮时光 2024-10-08 22:42:02

我将(再次)链接这篇精彩的文章

首先,[编译器]查看
直接范围,在这种情况下
C 类的范围,并列出
它能找到的所有函数都是
命名为 f (无论它们是否
可以到达,甚至走右边
参数数量)。 只有当它
不执行然后继续
“向外”进入下一个封闭区域
范围
[...]

所以,是的,fconst 版本是隐藏的,这是完全正常的。正如 Simone 所指出的,您可以使用 using 语句将 A::f 引入 C 范围。

I will (once more) link this great article :

First, [the compiler] looks in the
immediate scope, in this case the
scope of class C, and makes a list of
all functions it can find that are
named f (regardless of whether they're
accessible or even take the right
number of parameters). Only if it
doesn't does it then continue
"outward" into the next enclosing
scope
[...]

So yes, the const version of f is hidden, and that's perfectly normal. As pointed out by Simone, you can use a using statement to bring A::f in C scope.

莫多说 2024-10-08 22:42:02

是的。你可以这样写:

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)。

Yes, it is. You may write:

struct C : public A {
   virtual void f() { cout << "C::f" << endl; }
   using A::f;       
};

to make your code compile:

int main()
{
   const B b;
   b.f();   // prints "A::f const"

   const C c;
   c.f();   // prints "A::f const"
}

For more infos, you can refer to the 2010 C++ draft document's (which you can find here) chapter 10.2.(3-4).

长不大的小祸害 2024-10-08 22:42:02

隐藏基本成员的不是虚拟性或常量性(或缺乏),任何派生方法都会隐藏同名的基本方法。这样做是为了改善脆弱的基础阶级问题。

想象一下您的代码按如下方式工作(可能多年),删除了不相关的部分:

struct Base {
};

struct Derived : Base {
  void f(double);
}

void g(Derived &d) {
  d.f(42);
}

然后您需要修改 Base 以包含一个执行完全不同操作的方法,但是由于某种原因,您想将其命名为“f” :

struct Base {
  void f(int);
};

如果没有这条规则,每次派生调用 f 的使用都需要手动评估 - 如果 Base 位于提供给其他人的库中,您甚至可能无法访问这些其他用途!面对用户定义的(隐式)转换,情况会变得更糟。

相反,我们决定要求派生类明确声明它们希望使用 using 声明从 Base 导入给定名称。这条规则可能会令人惊讶,我不确定这对今天的语言是否有净好处,但他们没有问我——无论如何,当时我可能只能用两个音节的单词来回答他们。 :)

It is not the virtuality or const-ness (or lack thereof) that hides the base member, any derived method hides a base method of the same name. This was done to ameliorate the fragile base class problem.

Imagine your code was working (possibly for years) as below, with non-relevant parts removed:

struct Base {
};

struct Derived : Base {
  void f(double);
}

void g(Derived &d) {
  d.f(42);
}

Then you need to modify Base to include a method that does something completely different, but, for some reason, you want to name it 'f':

struct Base {
  void f(int);
};

Without this rule, every use of a Derived calling f needs to be manually evaluated — and if Base is in a library given to other people, you may not even have access to those other uses! It gets worse in the face of user-defined (implicit) conversions.

Instead, it was decided to require derived classes to explicitly state they want to import given names from Base with a using declaration. This rule can be surprising and I'm not sure it's a net benefit to the language today, but they didn't ask me — at the time, I could probably only have answered them with two-syllable words, anyway. :)

哽咽笑 2024-10-08 22:42:02

插入 using B::f;

struct C : public A { 
   using A::f;
   virtual void f() { cout << "C::f" << endl; } 
}; 

C++ 标准 2003. 13.2 p.1:

两个同名的函数声明引用同一个函数
如果它们在同一范围内并且
具有等效的参数声明(13.1)。一个功能
派生类的成员
相同
范围作为基类中同名的函数成员。

因此C::f隐藏了所有A::f

Insert using B::f;

struct C : public A { 
   using A::f;
   virtual void f() { cout << "C::f" << endl; } 
}; 

C++ Standard 2003. 13.2 p.1:

Two function declarations of the same name refer to the same function
if they are in the same scope and
have equivalent parameter declarations (13.1). A function
member of a derived class is not in
the same
scope as a function member of the same name in a base class.

Thus C::f hides all A::f.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文