Pregunta

Considere lo siguiente:

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

(estoy usando GCC.)

Así que parece que la versión const de f () se oculta en C. Esto tiene mucho sentido para mí, pero es un mandato de la norma?

¿Fue útil?

Solución

Yo (una vez más) enlazar este gran artículo :

En primer lugar, [compilador] miradas en el ámbito inmediato, en este caso el ámbito de aplicación de la clase C, y hace una lista de todas las funciones que puede encontrar que son llamado f (independientemente de si están accesible o incluso tomar la derecha número de parámetros). Sólo si no hace que luego continuar "Hacia fuera" en la siguiente envolvente alcance [...]

Así que sí, la versión de const f se oculta, y eso es perfectamente normal. Como ha señalado Simone, puede utilizar una declaración using para llevar A::f alcance C.

Otros consejos

Sí, lo es. Usted puede escribir:

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

para hacer que su compilación de código:

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

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

Para más informaciones, puede hacer referencia a la 2010 C ++ proyecto de documento (que se puede encontrar aquí ) capítulo 10.2. (3-4).

No es la virtualidad o const-dad (o la falta del mismo) que oculta el miembro base, cualquier cueros método derivado a un método de base del mismo nombre. Esto se hizo para mejorar el problema de la clase base frágil.

Imagine que su código funcionaba (posiblemente durante años) como abajo, con partes no relevantes eliminado:

struct Base {
};

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

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

A continuación, es necesario modificar la base para incluir un método que hace algo completamente diferente, pero, por alguna razón, usted quiere nombrarlo 'f':

struct Base {
  void f(int);
};

Sin esta regla, todos uso de un derivado llamando f debe ser evaluado de forma manual - y si la base está en una biblioteca dada a otras personas, puede que ni siquiera tienen acceso a esos otros usos! Se pone peor en la cara de conversiones definidas por el usuario (implícitas).

En lugar de ello, se decidió requerir clases derivadas a declarar explícitamente que quieren importar nombres de base con una declaración using. Esta regla puede ser sorprendente y no estoy seguro de que es un beneficio neto para el lenguaje de hoy, pero no me preguntó - en el momento, podría probablemente sólo que son respondidas con palabras de dos sílabas, de todos modos. :)

Insertar using B::f;

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

C ++ estándar 2003. 13.2 p.1:

dos declaraciones de función del mismo nombre se refieren a la misma función si están en el mismo alcance y tener declaraciones de parámetros equivalentes (13.1). Una función miembro de una clase derivada no en lo mismo alcance como un miembro de la función del mismo nombre en una clase base.

Así cueros C::f todo A::f.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top