Inheritance
Article Index
Inheritance
Polymorphism
Interfaces

Virtual functions

The whole issue of pointers 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.

Hiding methods

There is just a little more to say about inheritance in C# because if you don’t declare a method as virtual then overriding it isn’t quite as simple as in C++, say. C# doesn’t really have a default overriding method. If you declare a class and a method as:

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

and derive a class B from A then a C++ programmer might well override the method using:

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

This works but it generates a warning. The reason is that C# expects you to use the “new” keyword if you are redefining an inherited function:

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

This also works but without generating a warning.

In the C# reference manual this use of ‘new’ is said to ‘hide’ the inherited method. What this means is that the new definition is used in preference to the old one wherever it is in scope, i.e. wherever its definition applies. This appears to work just like overriding a non-virtual method but there are some subtleties. For example:

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

uses the new class B method. However if you use

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

then A’s original version of method is called.

This isn’t unreasonable as the original method wasn’t declared as virtual and so you wouldn’t expect late binding/polymorphism to work.

However the subtle part is that it still doesn’t work even if the original method was declared as virtual!

In other words the “new” keyword kills virtual inheritance! If you derive a class C from B and use the “override” keyword on a new version of the method then virtual inheritance works again.

The final twist is that the effect of the “new” keyword depends on whether or not the method is accessible. For example, if you declare the new method as private it only overrides the inherited method within the class – when used outside the class the inherited method is once again called.

Finally – why is the “new” keyword needed and why is only a warning generated when you forget to use it?

The reason is that you might very well create a class B that inherits from A and give it a new method called MyMethod. This method doesn’t need a “new” or an “override” keyword because it isn’t hiding or overriding an inherited method – it really is new. Everything is fine but suppose that later on class A is modified independently of class B and it has a MyMethod function added to it. Now there is a name collision between B.MyMethod and A.MyMethod. By default the B class always uses its own MyMethod which is presumably what its programmer would have wanted since they couldn’t have guessed that the owner of class A would add a MyMethod! Of course when the owner of class B recompiles the code they will be greeted with a warning that lets them know about the change. They can then either add the “new” keyword or “override” as appropriate.

Banner

<ASIN:0596514824>

<ASIN:0470191376>

<ASIN:1590598849>



 
 

   
RSS feed of all content
I Programmer - full contents
Copyright © 2014 i-programmer.info. All Rights Reserved.
Joomla! is Free Software released under the GNU/GPL License.