Domanda

Si consideri:

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

(sto usando GCC.)

Così sembra che la versione const di f () viene nascosto in C. Questo rende un sacco di senso per me, ma è mandato dalla norma?

È stato utile?

Soluzione

io (ancora una volta) collegare questo grande articolo :

  

In primo luogo, [il compilatore] guarda allo   applicazione immediata, in questo caso la   ambito di classe C, e fa un elenco di   tutte le funzioni si può trovare che sono   chiamato f (a prescindere dal fatto che siano   accessibili o addirittura prendere la destra   numero di parametri). Solo se   non lo fa poi continuare   "Passivo" nel prossimo racchiude   portata [...]

Quindi sì, la versione const di f è nascosto, e questo è perfettamente normale. Come sottolineato da Simone, è possibile utilizzare un'istruzione using per portare A::f portata C.

Altri suggerimenti

Sì, lo è. Si può scrivere:

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

per rendere il codice di compilazione:

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

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

Per maggiori informazioni, è possibile fare riferimento al 2010, C ++ bozza del documento (che potete trovare qui ) capitolo 10.2. (3-4).

Non è la virtualità o const-ness (o mancanza) che nasconde l'elemento di base, qualsiasi metodo nasconde derivato un metodo base dello stesso nome. Ciò è stato fatto per migliorare la fragile problema della classe base.

Immaginate il vostro codice funzionava (forse per anni), come di seguito, con parti non rilevanti rimosso:

struct Base {
};

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

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

Quindi è necessario modificare Base per includere un metodo che fa qualcosa di completamente diverso, ma, per qualche ragione, si vuole chiamarla 'f':

struct Base {
  void f(int);
};

Senza questa regola, tutti uso di un derivato chiamare f deve essere valutato manualmente - e se la base è in una libreria data ad altre persone, si può anche non avere accesso a tali altri usi! C'è di peggio di fronte alle conversioni definite dall'utente (impliciti).

Al contrario, si è deciso di richiedere classi derivate di affermare esplicitamente che vogliono importare i dati nomi di base con una dichiarazione secondo. Questa regola può essere sorprendente e non sono sicuro che sia un beneficio netto per il linguaggio di oggi, ma non mi ha chiesto - a quel tempo, avrei potuto probabilmente li ho risposto solo con le parole di due sillabe, in ogni caso. :)

Inserisci using B::f;

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

C ++ standard 2003. 13.2 p.1:

  

Due dichiarazioni di funzione con lo stesso nome si riferiscono alla stessa funzione   se sono nella stessa portata e       avere dichiarazioni dei parametri equivalenti (13.1). Una funzione   membro di una classe derivata non in   lo stesso       portata come membro funzione con lo stesso nome in una classe di base.

pelli Così C::f tutti A::f.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top