Deep C# - Inheritance
Written by MIke James   
Thursday, 27 August 2020
Article Index
Deep C# - Inheritance
Changing Types
Hiding Methods
Summary

Changing types

Now that all this is clear, what about:

Class A{};
Class B:A{};

that is class B inherits from A. If we follow this up by:

A MyA;
B MyB;
MyA=new B();

or slightly more subtly:

MyB=new B();
MyA=MyB;

In other words, can you use a reference to a base class to point to sub-classes?

Or put another way, can an A point to a B which inherits from?

The answer is yes and in this sense a reference variable to a base class provides a reference type that works with all of the derived classes. You can also go the other way and use a reference to a derived class to point to a base class.

For example:

MyB=(B) MyA;

But in this case you need an explicit typecast expression to indicate the conversion, i.e. (B).

If any of this doesn’t work at runtime then an exception is thrown.

If you want to avoid an exception do so using the “as” keyword.

For example:

MyB=MyA as B;

If this fails then MyB is just set to null. You can also use the “is” operator to make sure that a pointer specialisation will work.

For example:

If (MyA is B){MyA.bmethod}

Banner

Virtual functions

The whole issue of rerfences not pointing to the type of class they appear to point at brings us to the sticky subject of ‘polymorphism’.

What is polymorphism is a very good first question!

The answer to this can be difficult to follow so I’ll keep it simple.

If you have a class B which inherits from A you can override methods inherited from A by simply redefining them in B. Now we have two versions of the overridden method, A’s and B’s. If you create an instance of B then you would expect B’s version of the method to be used. If you create an instance of A you would expect A’s version of the method to be used. At the moment everything is fine and simple and C#, and all object-oriented languages, works exactly as you would expect in this case.

Now let’s make things slightly more difficult. Let’s use a reference variable to class A to actually point at an instance of class B. That is:

A MyA;
B MyB;
MyB=new B();
MyA=MyB;

Now when you use MyA.method which method do you expect to be used – class A’s version or class B’s version? Remember, the reference variable is a pointer to class A according to its declaration but it actually points at an instance of class B.

Novice programmers expect to get class B’s version of the method, i.e. the new one and the one that belongs to the instance being used, but they would be wrong. You actually get class A’s version of the method, i.e. the reference variable’s type determines what version of a method is actually called. This is also called ‘early binding’ because you can tell which class a reference variable actually refers to just by looking at its declared type even if later in the program it is made to point at a derived class.

If you want things to work so that class B’s version of the method is called then the method has to be declared as “virtual” in the base class. That is:

class A
{
virtual void method()
{
A’s version of the function;
}
}

Now when B inherits from A it can override the method in the usual way:

class B:A
{
override void method()
{
B’s version of the function;
}
}

Notice that you need the modifier “override” to override a virtual method. With this change now when you use a pointer the method called depends not on the pointer’s declared type but what sort of object it actually points at. That is, when you write:

A MyA;
B MyB;
MyB=new B();
MyA=MyB;
MyA.method();

it is the method belonging to the B class that is actually used. This behaviour is often called ‘polymorphism’ because the function you get depends on the instance actually being used. It is also called ‘late binding’ for similar reasons.

The next question you should be asking is, why not make every function virtual?

After all, the overriding of inherited functions is usually done because you want the new version of the function to be used whenever the new class is used. The only reason is that virtual methods are slightly less efficient to call and so languages such as C++ and C# give you the choice of how to define a function. If you think it unlikely that the method and the class will be used in a ‘late bound’ way then don’t bother declaring the method as virtual with all its overheads.

csharp



Last Updated ( Thursday, 27 August 2020 )