Sovraccarico del metodo di base nella class derivata

Quindi stavo giocando con C # per vedere se corrispondeva al comportamento in C ++ di questo post: http://herbsutter.com/2013/05/22/gotw-5-solution-overriding-virtual-functions/ quando mi sono imbattuto in questo strano comportamento:

public class BaseClass { public virtual void Foo(int i) { Console.WriteLine("Called Foo(int): " + i); } public void Foo(string i) { Console.WriteLine("Called Foo(string): " + i); } } public class DerivedClass : BaseClass { public void Foo(double i) { Console.WriteLine("Called Foo(double): " + i); } } public class OverriddenDerivedClass : BaseClass { public override void Foo(int i) { base.Foo(i); } public void Foo(double i) { Console.WriteLine("Called Foo(double): " + i); } } class Program { static void Main(string[] args) { DerivedClass derived = new DerivedClass(); OverriddenDerivedClass overridedDerived = new OverriddenDerivedClass(); int i = 1; double d = 2.0; string s = "hi"; derived.Foo(i); derived.Foo(d); derived.Foo(s); overridedDerived.Foo(i); overridedDerived.Foo(d); overridedDerived.Foo(s); } } 

Produzione

 Called Foo(double): 1 Called Foo(double): 2 Called Foo(string): hi Called Foo(double): 1 Called Foo(double): 2 Called Foo(string): hi 

Quindi apparentemente favorisce l’int implicitamente convertito per raddoppiare il più specifico Foo (int) dalla class base. O nasconde il Foo (int) dalla class base? Ma allora: perché Foo (stringa) non è nascosto? Si sente molto incoerente … Inoltre non importa se sostituisco Foo (int) o no; il risultato è lo stesso. Qualcuno può spiegare cosa sta succedendo qui?

(Sì, so che è una ctriggers pratica sovraccaricare i metodi di base in una class derivata – Liskov e tutti – ma non mi aspetterei che Foo (int) in OverriddenDerivedClass non venga chiamato ?!)

Per spiegare come funziona per l’esempio OverriddenDerivedClass :

Dai un’occhiata alla specifica C # per la ricerca dei membri qui: http://msdn.microsoft.com/en-us/library/aa691331%28VS.71%29.aspx

Questo definisce come viene eseguita la ricerca.

In particolare, guarda questa parte:

Innanzitutto, viene creato l’insieme di tutti i membri accessibili (Sezione 3.5) denominati N dichiarati in T e i tipi di base (Sezione 7.3.1) di T. Le dichiarazioni che includono un modificatore override sono escluse dal set.

Nel tuo caso, N è Foo() . A causa delle Declarations that include an override modifier are excluded from the set allora l’ override Foo(int i) viene escluso dal set.

Pertanto, rimane solo il Foo(double i) non sovrascritto Foo(double i) , e quindi è quello che viene chiamato.

Ecco come funziona per l’esempio OverriddenDerivedClass , ma questa non è una spiegazione per l’esempio DerivedClass .

Per spiegarlo, guarda questa parte della specifica:

Successivamente, i membri nascosti da altri membri vengono rimossi dal set.

Il Foo(double i) in DerivedClass nasconde Foo(int i) dalla class base, quindi viene rimosso dal set.

La cosa complicata qui è la parte che dice:

Tutti i metodi con la stessa firma di M dichiarati in un tipo base di S vengono rimossi dal set.

Potresti dire “Ma aspetta! Foo(double i) non ha la stessa firma di Foo(int i) , quindi non dovrebbe essere rimosso dal set!”.

Tuttavia, poiché c’è una conversione implicita da int a double, si considera che abbia la stessa firma, quindi Foo(int i) viene rimosso dal set.