2015-06-10 18 views
5

Non capisco cosa c'è di sbagliato in questo codice. Sembra una trappola incredibile!Strano comportamento quando si chiamano le funzioni virtuali

Questo codice:

class Foo 
{ 
    public: 
     virtual double foo(double x) const = 0; 
       double foo(int x) const { return (double)(x + x); } 
}; 

class Bar : public Foo 
{ 
    public: 
     virtual double foo(double x) const { return x * x; } 
}; 

int main() 
{ 
    Bar* b = new Bar; 
    Foo* f = b; 
    std::cout << b->foo(3) << " " << f->foo(3) << std::endl; 
    std::cout << b->foo(5.0) << " " << f->foo(5.0) << std::endl; 
    return 0; 
} 

stampa il seguente output:

9 6 
25 25 

deduco che Bar::foo(double) const si chiama con un cast implicita quando il tipo del puntatore è Bar*. Ma perché una cosa del genere è possibile senza alcun preavviso?

Lavoro con GCC 4.7.2. Compilato con g++ -Wall foobar.cpp -o foobar.exe

+2

penso che sarebbe meglio se si sceglie il secondo numero di un altro di 2. A causa 2 * 2 = 4 e 2 + 2 = 4. – nabroyan

+1

Sono curioso, hai lo stesso problema se il valore di ritorno di 'foo (int)' è anche 'int'? @nabroyan infatti, sarebbe ancora meglio usare lo stesso valore (ma di tipo diverso): '3' e' 3.0'. – Kryptos

+1

Possibile duplicato di http://stackoverflow.com/questions/1628768/why-does-an-overridden-function-in-the-derived-class-hide-other-overloads-of-the e http: // stackoverflow. it/questions/411103/function-with-same-name-but-different-signature-in-derivata-class – Kryptos

risposta

9

Ciò è dovuto al nome nascondersi.

Quando si dichiara una funzione denominata foo in Bar, si nascondono tutte le dichiarazioni con lo stesso nome in Foo.

Come tale, quando il tipo statico del puntatore è Bar, il compilatore unico trova la versione in Bar che prende una double, quindi converte implicitamente la int per soddisfare questo.

Se si desidera la versione int in Foo per essere visibile, aggiungere una dichiarazione using:

class Bar : public Foo 
{ 
    public: 
     using Foo::foo; 
//  ^^ makes the versions in Foo visible 
     virtual double foo(double x) const { return x * x; } 
}; 
2

Quando il tipo è Bar*, è visibile solo una versione del metodo, quella con il parametro double.

I metodi di base con lo stesso nome (ma firma diversa) sono nascosti.

Per renderli disponibili, è possibile utilizzare using Foo::foo nella classe derivata.

A seconda del compilatore, penso che potresti ricevere anche degli avvisi relativi alla conversione implicita o al fatto che apparentemente vuoi chiamare un metodo nascosto.

1

In Foo ci sono due overload di foo, uno che prende un double e un'altra che accetta un int.

In Bar c'è un sovraccarico di foo, quello che prende uno double. Questo overload nasconde tutte le funzioni con lo stesso nome dalle classi base. Questo è chiamato nome che si nasconde.

Una correzione potrebbe essere quella di impiegare utilizzando dichiarazione per portare gli altri foo sovraccarichi dalla classe base del perimetro di Foo classe derivata:

class Bar : public Foo 
{ 
    public: 
     using Foo::foo; 
     virtual double foo(double x) const { return x * x; } 
};