覆盖非const虚方法是否会隐藏const重载?

时间:2010-11-11 09:09:08

标签: c++ inheritance virtual const name-lookup

考虑:

#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语言中。这对我来说很有意义,但它是否符合标准?

4 个答案:

答案 0 :(得分:5)

我会(再次)链接这个伟大的article

  

首先,[编译器]查看   直接范围,在这种情况下   C类的范围,并列出   它能找到的所有功能   命名为f(无论是否为   可以接近甚至采取正确的方式   参数数量)。 仅限于此   不会这样做然后继续   “向外”进入下一个封闭   范围 [...]

所以是的,const f版本的using被隐藏了,这是完全正常的。正如Simone所指出的,您可以使用A::f语句将C置于{{1}}范围内。

答案 1 :(得分:3)

是的,确实如此。你可以写:

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 ++草案文档(您可以找到here)第10.2章。(3-4)。

答案 2 :(得分:3)

隐藏基本成员的不是虚拟性或持久性(或缺少它),任何派生方法都隐藏了同名的基本方法。这样做是为了改善脆弱的基类问题。

想象一下,您的代码正在运行(可能多年),如下所示,删除了不相关的部分:

struct Base {
};

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

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

然后你需要修改Base以包含一个完全不同的方法,但是,出于某种原因,你想要命名为'f':

struct Base {
  void f(int);
};

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

相反,决定要求派生类明确声明他们想要使用using声明从Base导入给定名称。这个规则可能令人惊讶,我不确定这对今天的语言有什么好处,但是他们没有问我 - 当时,我可能只能用双音节的单词回答它们。 :)

答案 3 :(得分:2)

插入using B::f;

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

C ++ Standard 2003. 13.2 p.1:

  

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

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