C#. Inheritance. Using constructors in classes for inheritance. The base keyword. Examples

Inheritance. Using constructors in classes for inheritance. The base keyword. Examples


Contents


1. The order in which class constructors that form a hierarchy are called

When creating an instance (object) of a class, the constructor of this class is called first. If class B is derived from base class A, then the constructor of base class A is called first, and then the constructor of derived class B. If classes form a hierarchy of several levels of inheritance, then first, class constructors of higher levels will be called in the form of a chain right up to the call of constructors of lower levels.

Figure 1 shows the sequence of calling constructors in the case of the inheritance of three classes with the names A, B, C. As you can see from the figure, the constructor of the base class A is always called first. The second is always called the constructor of class B, which is located at the middle level of the hierarchy. The last to be called is the constructor of class C, which is at the bottom of the hierarchy.

C#. Inheritance. Procedure for calling constructors in case of inheritance of three classes

Figure 1. Demonstration of the procedure for calling constructors in case of inheritance of three classes

The order of calling the constructors shown in Figure 1 is logically correct. This is due to the fact that derived classes are more specialized than the base class. The specialized part provides that it is superimposed on top of the general. Thus, the constructor of the derived class has the ability to use the inherited qualities of the constructor of the base class.

 

2. The base keyword. The need for application. General form

If classes form a hierarchy, then in a derived class there is a need to refer to an element of the base class. C# uses the base keyword for such cases. If the base class has hidden elements (declared as private), then these elements cannot be accessed using the base keyword.

The general form of using the base keyword in a derived class method is as follows:

base.class_element

where

  • class_element – an element of the base class that is not hidden (before which there is no private access modifier). An element of a base class can be a constructor, method (function), property, data field. There is a separate usage syntax for any of these elements (see paragraphs below).

 

3. Calling the base class constructor using the base keyword. General form. Examples

The constructor of the base class can be called explicitly from the constructor of the derived class. To do this, when declaring a constructor for a derived class, you need to use the base keyword. The general form of such declaration is as follows:

class ClassName
{
  // ...

  // Class constructor
  ClassName(parameters2) : base(parameters1)
  {
    // ...
  }
}

where

  • ClassName – name of the constructor of the derived class;
  • parameters1 – the parameters of the base class constructor. In order for the compiler not to throw errors, a constructor with exactly the same parameters must be explicitly declared in the base class;
  • parameters2 – constructor parameters of the derived class.

In string

...

ClassName(parameters2) : base(parameters1)
{
  // ...
}
...

the constructor of the base class is called first by calling

base(parameters1)

then the constructor body of ClassName() is called.

 



3.1. An example of calling a base class constructor using the base keyword. A hierarchy of three classes is used

The example demonstrates the inheritance of the three classes A, B, C. Class A is the base for class B. In turn, class B is basic to class C.

using System;
using static System.Console;

namespace ConsoleApp1
{
  // Base class A
  class A
  {
    public int a;

    // Class A constructor - with one parameter
    public A(int _a)
    {
      a = _a;
      WriteLine("Constructor A(int): a = {0}", a);
    }
  }

  // Class B - derived from Class A
  class B : A
  {
    public int b;

    // Class B constructor with 1 parameter,
    // implicitly calls constructor A() of class A
    public B(int _b) : base(0)
    {
      b = _b;
      WriteLine("Constructor B(int): b = {0}", b);
    }
  }

  // Class C - derived from Class B
  class C : B
  {
    public int c;

    public C(int _c) : base(0)
    {
      c = _c;
      WriteLine("Constructor C(int): c = {0}", c);
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // 1. When creating an objB instance
      // constructors are called in the following sequence: A(int) => B(int)
      B objB = new B(4);
      WriteLine("------");

      // 2. When creating an objC instance
      // the sequence of calling the constructors is as follows:
      // A(int)=>B(int)=>C(int)
      C objC = new C(5);
    }
  }
}

As you can see from the above code, in the class, the constructor of class A is called from the constructor of class B using the string

...

public B(int _b) : base(0) // base(0) => A(0)
{
  ...
}

...

Similarly, in class C, the constructor of class B is called from the constructor C(int)

...

public C(int _c) : base(0) // base(0) => B(0)
{
  ...
}

...

The result of the program

Constructor A(int): a = 0
Constructor B(int): b = 4
------
Constructor A(int): a = 0
Constructor B(int): b = 0
Constructor C(int): c = 5

 

3.2. Calling the base class constructor using base keyword. Example Human=>Worker classes

The base class Human is set. The following elements are declared in the class:

  • the internal field name, which implements the surname and name of the person;
  • constructor with 1 parameter Human(string);
  • property Name. Used to access the internal name field.

From the Human class, the Worker class is inherited. The Worker class implements the following elements:

  • internal field – date of hiring date in string format;
  • internal field – position position;
  • a constructor with three parameters Worker(string, string, string), which sets the internal fields of the derived Worker class and the base class Human. To call the base class constructor, use the base keyword;
  • property Date to access the internal field date;
  • property Position to access the internal field position.

The text of the program created using the Console Application template is as follows:

using System;
using static System.Console;

namespace ConsoleApp1
{
  // Base class Human
  class Human
  {
    // 1. Hidden internal field
    private string name;

    // 2. Constructor with 1 parameter
    public Human(string _name)
    {
      name = _name;
      WriteLine("Name {0} is set.", name);
    }

    // 3. Property Name - required to access name
    public string Name
    {
      get { return name; }
      set { name = value; }
    }
  }

  // Class Worker - derived from class Human
  class Worker : Human
  {
    // 1. Internal fields
    private string date; // Date of employment
    private string position; // Position

    // 2. Constructor with 3 parameters,
    // calls the constructor of the base class Human
    // with a call to base(name).
    // First, the constructor base(name)=>Human(name) is executed,
    // then the Worker(...) constructor is used
    public Worker(string name, string _date, string _position) : base(name)
    {
      date = _date;
      WriteLine("Date {0} is set.", date);
      position = _position;
      WriteLine("Position {0} is set.", position);
    }

    // 3. Property Date
    public string Date
    {
      get { return date; }
      set { date = value; }
    }

    // 4. Property Position
    public string Position
    {
      get { return position; }
      set { position = value; }
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // When declaring an instance of the Worker class
      // first, the constructor of the Human class is called,
      // then the constructor of the Worker class is called.
      Worker wr = new Worker("J. Johansson", "29.02.2020", "Manager");

      WriteLine("---------");
      wr.Name = "K. Night";
      WriteLine("wr.Name = {0}", wr.Name);
      wr.Date = "01.03.2020";
      WriteLine("wr.Date = {0}", wr.Date);
    }
  }
}

The result of the program

Name J. Johansson is set.
Date 29.02.2020 is set.
Position Manager is set.
---------
wr.Name = K. Night
wr.Date = 01.03.2020

 

4. When is it not necessary to use the base keyword to invoke the constructor of the base class? Example

In order not to use the base keyword in the constructor of the derived class, you need to implement the constructor without parameters in the base class. Then this constructor will be called implicitly from all the constructors of the derived class. At the same time, both the base and the derived classes may contain different implementations of the constructors.

Example. Two classes are given with the names A, B. There are 2 constructors declared in class A:

  • without parameters A();
  • with parameter A(int).

Class B is derived from class A. In class B, when declaring a constructor, it is not necessary to use the base keyword, since in class A, a constructor without parameters is declared.

using System;
using static System.Console;

namespace ConsoleApp1
{
  // Base class A
  class A
  {
    public int a;

    // Constructor of class A - without parameters
    public A()
    {
      a = 1;
      WriteLine("Constructor A(): a = {0}", a);
    }

    // Constructor of class A - with one parameter
    public A(int _a)
    {
      a = _a;
      WriteLine("Constructor A(int): a = {0}", a);
    }
  }

  // Class B - derived from class A
  class B : A
  {
    public int b;

    // The constructor of class B without parameters,
    // implicitly calls constructor A() of class A
    public B()
    {
      b = 2;
      WriteLine("Constructor B(): b = {0}", b);
    }

    // Class B constructor with 1 parameter,
    // implicitly calls constructor A() of class A
    public B(int _b)
    {
      b = _b;
      WriteLine("Constructor B(int): b = {0}", b);
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // 1. When creating an objB instance, the constructors
      // are called in the following sequence: A()=>B()
      B objB = new B();
      WriteLine("------");

      // 2. When creating an objB2 instance, the constructors
      // are called in the following sequence: A()=>B(int)
      B objB2 = new B(5);
    }
  }
}

If in class A() we remove the constructor declaration without parameters

public A()
{
  // ...
}

then the compiler will throw an error

There is no argument given that corresponds to the required formal parameter _a of A.A(int)

 

5. An example of explicitly calling the base class constructor using the base keyword without specifying parameters

If a constructor without parameters A() is declared in base class A, the base keyword without parameters is allowed.

For example.

// Base class A
class A
{
  // ...

  // Constructor of class A - without parameters
  public A()
  {
    // ...
  }

  // ...
}

// Class B - derived from class A
class B : A
{
  // ...

  // The constructor of class B without parameters,
  // explicitly calls constructor A() of class A
  public B() : base() // it is also possible
  {
    // ...
  }

  // ...
}

 

6. Implicit invocation of base class constructors using an example of a hierarchy of three classes

The example demonstrates the hierarchy of constructor calls without the base keyword for classes A, B, C. The base keyword is used implicitly.

using System;
using static System.Console;

namespace ConsoleApp1
{
  // Base class A
  class A
  {
    public int a;

    // Constructor of class A
    public A()
    {
      a = 1;
      WriteLine("Constructor A(): a = {0}", a);
    }
  }

  // Class B - derived from class A
  class B : A
  {
    public int b;

    // Constructor of class B,
    // implicitly calls the constructor of class A
    public B()
    {
      b = 2;
      WriteLine("Constructor B(): b = {0}", b);
    }
  }

  // Class C - derived from class B
  class C : B
  {
    public int c;

    // Constructor of class C,
    // implicitly invokes class B constructor
    public C()
    {
      c = 3;
      WriteLine("Constructor C(): c = {0}", c);
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // 1. When creating an objB instance, the constructors
      // are called in the following sequence: A()=>B()
      B objB = new B();
      WriteLine("------");

      // 2. When creating an objC instance, the sequence of
      // calling the constructors: A()=>B()=>C()
      C objC = new C();
      WriteLine("------");
    }
  }
}

The result of the program

Constructor A(): a = 1
Constructor B(): b = 2
------
Constructor A(): a = 1
Constructor B(): b = 2
Constructor C(): c = 3
------

 


Related topics