Question

Considérez:

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

(j'utilise GCC.)

Il semble donc que la version const de f () qui est caché en C. Cela fait beaucoup de sens pour moi, mais est-il mandaté par la norme?

Était-ce utile?

La solution

Je (encore une fois) un lien entre ce grand article :

  regarde

D'abord, [le compilateur] dans le   champ d'application immédiate, dans ce cas,   la portée de la classe C, et fait une liste des   toutes les fonctions qu'il peut trouver que sont   nommé f (indépendamment du fait qu'ils sont   accessible ou même prendre le droit   nombre de paramètres). Seulement si   ne continue-t-il alors   « Vers l'extérieur » dans la prochaine enfermant   portée [...]

Alors oui, la version const de f est caché, et qui est tout à fait normal. Comme l'a souligné Simone, vous pouvez utiliser une instruction using pour apporter A::f portée de C.

Autres conseils

Oui, il est. Vous pouvez écrire:

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

pour faire votre compilation de code:

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

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

Pour plus d'infos, vous pouvez consulter le projet de document de 2010 C ++ (que vous pouvez trouver ) chapitre 10.2. (3-4).

Il est le virtuality ou const-ness (ou son absence) qui cache les membres de base, toute méthode dérivés cache une méthode de base du même nom. Cela a été fait pour améliorer le problème fragile de la classe de base.

Imaginez votre code fonctionnait (peut-être pendant des années) comme ci-dessous, avec des parties non pertinentes supprimées:

struct Base {
};

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

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

Ensuite, vous devez modifier la base pour inclure une méthode qui fait quelque chose de complètement différent, mais, pour une raison quelconque, vous voulez le nommer « f »:

struct Base {
  void f(int);
};

Sans cette règle, tous l'utilisation d'un dérivé d'appel f doit être évaluée manuellement - et si la base est dans une bibliothèque donnée à d'autres personnes, vous ne pouvez pas même avoir accès à ces autres utilisations! Il y a pire en face des conversions (implicites) définies par l'utilisateur.

Au lieu de cela, il a été décidé d'exiger des classes dérivées de dire explicitement qu'ils veulent importer des noms donnés de base avec une déclaration à l'aide. Cette règle peut être surprenant et je ne suis pas sûr que c'est un avantage net pour la langue d'aujourd'hui, mais ils ne me demandez pas - à l'époque, je ne pouvais probablement leur ai répondu avec deux syllabes des mots, de toute façon. :)

Insérer using B::f;

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

C ++ standard 2003. 13.2 p.1:

  

Deux déclarations de fonction du même nom se réfèrent à la même fonction   si elles sont dans la même portée et       ont déclarations de paramètres équivalents (13.1). Une fonction   membre d'une classe dérivée n'est pas   le même       champ d'application en tant que membre de la fonction du même nom dans une classe de base.

Ainsi C::f cache tout A::f.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top