So I was playing with C# to see if it matched C++ behavior from this post: http://herbsutter.com/2013/05/22/gotw-5-solution-overriding-virtual-functions/ when I came across this very strange behavior:
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);
}
}
Output
Called Foo(double): 1
Called Foo(double): 2
Called Foo(string): hi
Called Foo(double): 1
Called Foo(double): 2
Called Foo(string): hi
So apparently it favors the implicitly converted int to double over the more specific Foo(int) from the base class. Or does it hide the Foo(int) from the base class? But then: why isn't Foo(string) hidden? Feels very inconsistent... It also does not matter if I override Foo(int) or not; the outcome is the same. Can anyone explain what's going on here?
(Yes I know that it is bad practice to overload base methods in a derived class - Liskov and all - but I still wouldn't expect that Foo(int) in OverriddenDerivedClass isn't called?!)
In C#, just like in C++, there is no overload resolution between class Base and class Derived. Also, there is no overloading across scopes and derived class scopes are not an exception to this general rule.
All overloaded operators except assignment (operator=) are inherited by derived classes.
Using a qualified-id to call a base class' function works irrespectively of what happens to that function in the derived class - it can be hidden, it can be overridden, it can be made private (by using a using-declaration), you're directly accessing the base class' function when using a qualified-id.
base (C# Reference)The base keyword is used to access members of the base class from within a derived class: Call a method on the base class that has been overridden by another method. Specify which base-class constructor should be called when creating instances of the derived class.
To explain how it works for the OverriddenDerivedClass
example:
Have a look at the C# spec for member lookup here: http://msdn.microsoft.com/en-us/library/aa691331%28VS.71%29.aspx
That defines how the lookup is done.
In particular, look at this part:
First, the set of all accessible (Section 3.5) members named N declared in T and the base types (Section 7.3.1) of T is constructed. Declarations that include an override modifier are excluded from the set.
In your case, N
is Foo()
. Because of Declarations that include an override modifier are excluded from the set
then the override Foo(int i)
is excluded from the set.
Therefore, only the non-overridden Foo(double i)
remains, and thus it is the one that is called.
That is how it works for the OverriddenDerivedClass
example, but this is not an explanation for the DerivedClass
example.
To explain that, look at this part of the spec:
Next, members that are hidden by other members are removed from the set.
The Foo(double i)
in DerivedClass
is hiding the Foo(int i)
from the base class, so it is removed from the set.
The tricky thing here is the part that says:
All methods with the same signature as M declared in a base type of S are removed from the set.
You might say "But wait! Foo(double i)
doesn't have the same signature as Foo(int i)
, so it shouldn't be removed from the set!".
However, because there is an implicit conversion from int to double, it is considered to have the same signature, so Foo(int i)
is removed from the set.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With