 .NET 1.1C# Inheritance and Constructors
The nineteenth part of the C# Object-Oriented Programming tutorial continues the discussion of inheritance. Constructor and destructor functionality is not inherited by subclasses but these can still use the constructors defined in their base class.
Inheritance
In the previous part of the C# Object Oriented Programming tutorial, we examined the concept of inheritance and its application in C#. Using inheritance, methods, properties, events, indexers, operators and internal variables that are declared in a base class are automatically made available to its subclasses.
Constructors and Inheritance
Unlike the above class behaviour, constructors that are declared within a base class are not inherited by subclasses. As with any other class, a subclass with no constructors defined is provided with a default constructor that provides no explicit functionality. The constructors from the base class are not made available when creating new subclass object instances.
When a subclass is instantiated, the standard behaviour is for the default constructor of the base class to be called automatically. In this way, the base constructor can initialise the base class before the subclass' constructor is executed.
To demonstrate the order of execution of the constructors, examine the following sample code. The first class is the main Program class within a console application. It simply instantiates a MySubclass object. MyBaseClass is a class with a single constructor that outputs a message to the console. MySubclass inherits from MyBaseClass and also outputs to the console when constructed. Note the order in which the messages appear.
class Program
{
static void Main()
{
MySubclass test = new MySubclass();
}
}
class MyBaseClass
{
public MyBaseClass()
{
Console.WriteLine("MyBaseClass constructor called.");
}
}
class MySubclass : MyBaseClass
{
public MySubclass()
{
Console.WriteLine("MySubclass constructor called.");
}
}
/* OUTPUT
MyBaseClass constructor called.
MySubclass constructor called.
*/
This behaviour is repeated for complex hierarchies of inherited classes. Where there are more than two levels of inheritance, the least specialised class' constructor is called first with each constructor down the tree called in turn until the specifically instantiated class' constructor is finally executed.
Destructors and Inheritance
Destructors are similar to constructors in inheritance scenarios, as these too are not inherited. However, as a destructor cannot be called directly, this is not a drawback.
When an object is out of scope and being removed from memory, its destructor is called automatically. If the object is based upon a subclass, the superclass' destructor will be called too. This happens in the reverse order to that of constructors. The subclass' destructor is called first, followed by the base class' constructor.
The order of execution of destructors can be demonstrated by modifying the earlier example. Begin by adding a destructor to the "MyBaseClass" class as follows:
~MyBaseClass()
{
Console.WriteLine("MyBaseClass destructor called.");
}
Now add a similar destructor to the "MySubclass" file:
~MySubclass()
{
Console.WriteLine("MySubclass destructor called.");
}
Finally, execute the program. Note the order in which the messages are displayed:
MyBaseClass constructor called.
MySubclass constructor called.
MySubclass destructor called.
MyBaseClass destructor called.
Calling Specific Base Constructors
As described above, the standard behaviour for a subclass is to call the base class' default constructor on instantiation. There are two situations where this is inappropriate. Firstly, the base class may contain much more useful constructors that accept parameters. Secondly, if the base class does not include a default constructor the program will not compile unless an alternative is provided.
One base constructor will always be called when a new object is created. However, the choice of base constructor to execute can be changed using the base keyword. The base keyword is used in a similar manner as the "this" keyword in constructor overloading. The constructor declaration is declared as usual, then a colon character (:) is appended. After the colon the base keyword and the parameter list of the base constructor to call is provided. Each parameter specified in the call to the base class must match one of those in the new constructor or be a literal value.
public Constructor(parameters-1) : base(parameters-2)
{
}
To demonstrate the execution of base constructors, add a new constructor to "MyBaseClass". This constructor will accept a single integer parameter, which will be outputted to the console.
public MyBaseClass(int aNumber)
{
string output;
output = string.Format("MyBaseClass created with value {0}.", aNumber);
Console.WriteLine(output);
}
We can now add a constructor to "MySubclass" that calls the new base class constructor when an object is instantiated:
public MySubclass(int startValue) : base(startValue)
{
string output;
output = string.Format("MySubclass created with value {0}.", startValue);
Console.WriteLine(output);
}
To test the example, the Main method in the Program class must be updated. In the new version, a "MySubclass" object is created using the new constructor.
static void Main()
{
MySubclass test = new MySubclass(10);
}
/* OUTPUT
MyBaseClass created with value 10.
MySubclass created with value 10.
MySubclass destructor called.
MyBaseClass destructor called.
*/
Using Protected Constructors
In the previous article in this series I introduced the protected scope and associated access modifier. Using this scope, a constructor can be declared as protected in a base class. This constructor will not be available for use externally except within subclasses.
To show the use of protected constructors, modify the parameter-less constructor of MyBaseClass to make it protected:
protected MyBaseClass()
{
Console.WriteLine("MyBaseClass constructor called.");
}
If you modify the Main method as follows, you will see that the default constructor is no longer available for general use and the code will not compile.
static void Main()
{
MyBaseClass test = new MyBaseClass();
}
The protected constructor is still available to the subclass. We can demonstrate this by modifying the Main method again. Try executing the following code.
static void Main()
{
MySubclass test = new MySubclass();
}
/* OUTPUT
MyBaseClass constructor called.
MySubclass constructor called.
MySubclass destructor called.
MyBaseClass destructor called.
*/
|