Article Index

Chapter Three

Inheritance is a simple idea, until you try to make use of it.



Inheritance is an idea that beginners take a long time to understand properly and even when they do there is a lot of scope for making mistakes. C#’s inheritance mechanisms are particularly clean and easy but let’s make sure that we know how they work.

The fundamental class declaration in C# takes the form:

class name:base class name

If you don’t specify a base class then the default class called “object” is used. Only a class can inherit and only from another class – structs always inherit from “object” and can’t be used to create new structs or classes by inheritance. If you want to create a class that can’t be used as a base class then simply add the “sealed” modifier to the start of the class definition.

Notice that C# only allows single inheritance which is by contrast to C++ and something of a relief!

If you think that C++’s ability to create classes from more than one base class is a good idea then you haven’t seen some of the stranger things that can happen when this powerful facility gets out of hand.

There is no doubt that single inheritance is safer and can do everything that multiple inheritance can if you are prepared to approach it in the right way.

When you create an instance of a class you first create a reference variable of the correct type. For example:

class A {};
A MyA;

doesn’t create an instance of A; only a reference variable capable of pointing to an object of type A – you have to be careful how you phrase such ‘pointing to an object’ because C# doesn’t have pointers as such but we all know what is going on here!

After declaring a reference variable you can set it to point to new instance of the class using:

MyA=new A();

Of course you can put both parts together to read:

A MyA=new A();

One of the advantages of single inheritance is that if you want to call the base class’s methods you can do so with a single keyword “base”.

For example, if B inherits a method “show” from A then B can call the method using:;

A special case of using the base classes methods is the inherited constructor. If a class inherits from another class then the base class default constructor is automatically called before the child class’s own constructor. If the base class also inherits from another class its constructor is called first and so on until we reach the first class in the inheritance chain.

If a class defines an explicit constructor and inherits from another class the explicit constructor must call one of the base class’s constructors. If the base class only has constructors that use parameters the child class has to call one of them using the “base” keyword. For example:

class MyClass2:MyClass1
public MyClass2:base(7)
rest of constructor

In this case the MyClass2 constructor calls the MyClass1(int n) constructor before continuing with its own instructions.

Notice that the “this” keyword can nearly always be used to make clear that the version of something to be used is the class’s own version and “base” can be used to indicate that the possibly hidden base class’s version should be used.

Changing pointer 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();

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 pointer 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}