Overloading and Inheritance in C++, C#, and VB.NET
Let's consider these three pieces of code in C++, C# and VB.NET:
C++ | C# | VB.NET |
---|---|---|
#include <stdio.h> class Base { public: virtual void f(int x, int y) { printf("Base::f(%d,%d)\n", x, y); } void f(int x) { f(x,x); } }; class Derived : public Base { public: virtual void f(int x, int y) { printf("Derived::f(%d,%d)\n", x, y); } }; int main() { Derived D; D.f(3); // <-------- error! return 0; } |
using System; class Base { public virtual void f(int x, int y) { Console. WriteLine("Base::f({0},{1})", x, y); } public void f(int x) { f(x,x); } } class Derived : Base { public override void f(int x, int y) { Console. WriteLine("Derived::f({0},{1})", x, y); } } class Program { static void Main(string[] args) { Derived D = new Derived(); D.f(3); // <-------- OK } } |
Imports System Class Base Public Overridable _ Sub f(ByVal x As Integer, ByVal y As Integer) Console. _ WriteLine("Base::f({0},{1})", x, y) End Sub Public Sub f(ByVal x As Integer) f(x, x) End Sub End Class Class Derived Inherits Base Public Overrides _ Sub f(ByVal x As Integer, ByVal y As Integer) Console. _ WriteLine("Derived::f({0},{1})", x, y) End Sub End Class Class Program Shared Sub Main() Dim D As New Derived D.f(3) ' <-------- error! End Sub End Class |
They seem to be exactly equivalent, but are they? Only C# version works
as expected and prints "Derived::f(3,3)
". C++ and VB.NET versions
give compilation error, saying that Derived::f
does not take one
argument. Why is that? Shouldn't the compiler automatically recognize that
Base::f
must be called in this case?
The short answer is no. Longer answer is "no, because of different name hiding rules in C++, C# and VB.NET
C++ : Hiding By Name
In C++ the situation is simple, albeit somewhat unexpected.
Member of derived class hides all members of the base classes
with the same name. Note, that signature (i.e. types
of parameters), or accessibility of members (public
, protected
,
or private
) is not taken into account at all.
Private member of derived class can hide public member of base
class, as in the code below:
class Base { public: void f(int, int) {}; }; class Derived : public Base { private: void f() {}; }; void Test() { Derived D; D.f(3,3); // <-------- error! return 0; } |
C# : Hiding By Signature
In C# name hiding is done by signature, i.e. Derived.f(int,int)
may hide Base.f(int,int)
, but not Base.f(int)
.
This is why our first example compiled and worked in C#.
There are two other differences between C# and C++ with respect
to name hiding. Unlike C++, C# takes into account visibility of names.
If a name is not accessible in particular scope, it will not hide
a name, which is accessible. E.g., the following code will compile
and will invoke Base.f()
:
using System; class Base { public void f() { Console.WriteLine("Base.f()"); } } class Derived : Base { new private void f() { Console.WriteLine("Derived.f()"); } } class Program { static void Main(string[] args) { Derived D = new Derived(); D.f(); // <---------- OK } } |
The second difference between C# and C++ is that C# requires to
use keyword new
when name hiding occurs. If keyword
new
is omitted, C# compiler will issue a warning.
VB.NET : Hiding Of Your Choice
VB.NET is the most flexible among the three languages, and the most confusing. By default it follows the C++ model (hiding by name) with some relaxations. In particular, private member of derived class does not hide public member of base class:
Class Base Public Sub f(ByVal x As Integer) Console.WriteLine("Base.f({0})", x) End Sub End Class Class Derived Inherits Base Private Shadows Sub f() Console.WriteLine("Derived.F()") End Sub End Class Class Program Public Shared Sub Main() Dim D As New Derived D.f(3) ' <---------- OK End Sub End Class |
Note the keyword Shadows
used to specify hiding by name.
This is a default behavior, but without Shadows
keyword
VB.NET compiler will issue a warning.
VB.NET can be switched to hiding by signature by using Overloads
keyword. For example, we can make our first example work, if we add Overloads
to the definition of method Derived.f()
.
Imports System Class Base Public Overridable Sub f(ByVal x As Integer, ByVal y As Integer) Console.WriteLine("Base::f({0},{1})", x, y) End Sub Public Sub f(ByVal x As Integer) f(x, x) End Sub End Class Class Derived Inherits Base Public Overloads Overrides Sub f(ByVal x As Integer, ByVal y As Integer) Console.WriteLine("Derived::f({0},{1})", x, y) End Sub End Class Class Program Shared Sub Main() Dim D As New Derived D.f(3) ' <-------- OK End Sub End Class |
Another interesting point about VB.NET is that Shadows
and
Overrides
keywords cannot be used together (while Shadows
and Overloads
can). This creates an interesting situation.
If we compile our original example from the top of this page, there will
be a warning when defining Derived.f(int,int)
, because it
shadows Base.f(int)
(pardon me C#-like notation for signatures).
Text of the warning recommends to add Shadows
keyword to the
definition, but if we do as told, we get error, saying Shadows
and Overrides
cannot be used together. This can be viewed
as some lack of consistency in VB.NET language.