Question: Can an abstract class have a constructor? If so what is the use?
Answer: Yes, an abstract class can have a constructor. In general, a class constructor is used to initialize fields. Along the same lines, an abstract class constructor is used to initialize fields of the abstract class.
Let's see an example.
Step 1
First we will create a console application named InterviewQuestionPart7.
Step 2
Then we will create an abstract class named customer and include a private field, the return type of this private field is Guid that is a Globally Unique Identifier. Now to expose this field to the external world, let's include a public property and we want this property to be read-only and we will include only Get accesses.
Now for initializing this private field of the abstract class we will create a constructor within this abstract class that has the same name of the class and does not have a return type. So let's use this constructor to initialize the private field. We will therefore now initialize it as a new Globally Unique Identifier (GUID), so we will invoke the NewGuid() method on the Guid class using the following code.
- using System;
- using System.Collections.Generic;
- using System.Text;
-
- namespace InterviewQuestionPart7
- {
- class Program
- {
- static void Main(string[] args)
- {
-
- }
- public abstract class Customer
-
- {
- public Customer()
- {
- this._id = Guid.NewGuid();
- }
- private Guid _id;
- public Guid ID
- {
- get
- {
- return this._id;
- }
- }
-
- }
-
- }
- }
Step 3
Now in our business we have two types of customers, CorporateCustomer and SavingsCustomer. We will create two classes, CorporateCustomer class and Savings Customer class, and they will be derived from our Customer abstract class.
Now we will create an instance of the CorporateCustomer class derived from the Customer class and the Customer class has the property public ID, so it should be available on the instance of CorporateCustomer class. And similarly we will create an instance of a SavingsCustomer class and print the property using the following code.
- using System;
- using System.Collections.Generic;
- using System.Text;
-
- namespace InterviewQuestionPart7
- {
- class Program
- {
- static void Main(string[] args)
- {
- CorporateCustomer cc = new CorporateCustomer();
- Console.WriteLine(cc.ID);
-
- SavingsCustomer sc = new SavingsCustomer();
- Console.WriteLine(sc.ID);
-
- }
- public abstract class Customer
-
- {
- public Customer()
- {
- this._id = Guid.NewGuid();
- }
- private Guid _id;
- public Guid ID
- {
- get
- {
- return this._id;
- }
- }
-
- }
- public class CorporateCustomer:Customer
- {
-
- }
- public class SavingsCustomer:Customer
- {
-
- }
- }
- }
Now let's run and see the output we get. As expected we get the Globally Unique Identifier for the CorporateCustomer class and the SavingsCustomer class.
So here within the abstract class we are using the constructor to initialize the fields of the abstract class.
Step 4
We would provide a constructor for an abstract class if we want to initialize certain fields of the abstract class before the instantiation of a child class takes place.
Here we have two child classes, CorporateCustomer and SavingsCustomer, derived from the abstract Customer class.
Now we want a Globaly Unique Identifier to be assigned to the _id field, even before an instance of either the CorporateCustomer or SavingsCustomer to be created. this is another use case where we use a constructor within the abstract class.
Let's actually prove that the constructor of the abstract class is called before even the child class constructor. For proving that let's include the constructor in both of the derived classes with the following code.
- using System;
- using System.Collections.Generic;
- using System.Text;
-
- namespace InterviewQuestionPart7
- {
- class Program
- {
- static void Main(string[] args)
- {
- CorporateCustomer cc = new CorporateCustomer();
- Console.WriteLine(cc.ID);
-
- SavingsCustomer sc = new SavingsCustomer();
- Console.WriteLine(sc.ID);
-
- }
- public abstract class Customer
-
- {
- public Customer()
- {
- this._id = Guid.NewGuid();
- }
- private Guid _id;
- public Guid ID
- {
- get
- {
- return this._id;
- }
- }
-
- }
- public class CorporateCustomer:Customer
- {
- public CorporateCustomer()
- {
-
- }
-
- }
- public class SavingsCustomer:Customer
- {
-
- public SavingsCustomer()
- {
-
- }
- }
- }
- }
Now we will create a breakpoint on the CorporateCustomer constructor and SavingsCustomer constructor, in the abstract class constructor and within the Main method. Now Debug the program and see what will happen.
First we try to create an instance of the CorporateCustomer derived class and now we will press F11/F10 until it gets to the CorporateCustomer constructor (that is the child class constructor) and try to execute it. Now we press the F10 and notice that what happens is it comes to the base class constructor. Now again we will press F10 and it executes and assigns the Globally Unique Identifier. Now again we will press the F10 and it will get to the constructor of the CorporateCustomer. Then it will execute the child class constructor. So that proves that the constructor of the parent class is called before the derived class constructor. So this this another use case where we would use the a constructor within the abstract class.
An abstract class constructor can also be used to execute code that is relevant for every child class.
This prevents duplicate code.
Step 5
Now if we look, the ID field is common to both the CorporateCustomer class and the SavingsCustomer class and it is present in the abstract class. If we were to move this code to the derived classes then we would end up with this duplicated code in both of the derived classes. Now we will move this code to both of the classes. And in the base class we remove the constructor and make the property abstract. And we need to override the property in the derived classes using the following code.
- using System;
- using System.Collections.Generic;
- using System.Text;
-
- namespace InterviewQuestionPart7
- {
- class Program
- {
- static void Main(string[] args)
- {
- CorporateCustomer cc = new CorporateCustomer();
- Console.WriteLine(cc.ID);
-
- SavingsCustomer sc = new SavingsCustomer();
- Console.WriteLine(sc.ID);
-
- }
- public abstract class Customer
-
- {
- public abstract Guid ID
- {
- get;
-
- }
-
- }
- public class CorporateCustomer:Customer
- {
- public CorporateCustomer()
- {
- this._id = Guid.NewGuid();
- }
- private Guid _id;
- public override Guid ID
- {
- get
- {
- return this._id;
- }
- }
-
- }
- public class SavingsCustomer:Customer
- {
-
- public SavingsCustomer()
- {
- this._id = Guid.NewGuid();
- }
- private Guid _id;
- public override Guid ID
- {
- get
- {
- return this._id;
- }
- }
- }
- }
- }
Now we will run this and we will get the same output like this.
But at the moment since we have delegated the responsibility of initializing the common field of the derived class we have duplicated code in both of the classes.
So an abstract class constructor can also be used to execute code that is relevant for every child class. This prevents duplicate code.
Note: Abstract classes can't be directly instantiated. The abstract class constructor gets executed from a derived class. So, it is a good practice to use a protected access modifier with an abstract class constructor. Making it public doesn't make sense.
Step 6
Now to understand this we reset move back the implementation in the base class. We have the public constructor in the abstract class.
So we create an instance of the abstract class explicitly. Now to see what will happen, let's build it. We get an error. Here it makes sense.
- using System;
- using System.Collections.Generic;
- using System.Text;
-
- namespace InterviewQuestionPart7
- {
- class Program
- {
- static void Main(string[] args)
- {
-
- Customer c = new Customer();
-
- CorporateCustomer cc = new CorporateCustomer();
- Console.WriteLine(cc.ID);
-
- SavingsCustomer sc = new SavingsCustomer();
- Console.WriteLine(sc.ID);
-
- }
- public abstract class Customer
-
- {
- public Customer()
- {
- this._id = Guid.NewGuid();
- }
- private Guid _id;
- public Guid ID
- {
- get
- {
- return this._id;
- }
- }
-
- }
- public class CorporateCustomer:Customer
- {
-
- }
- public class SavingsCustomer:Customer
- {
-
- }
- }
- }
Step 7
Now the constructor of the abstract class is called from the derived class so it should be available in the derived class and we know that we cannot create an instance of the base class explicitly like this so having the access modifier public does not make sense so now we will use the protected modifier and it is a good practice so now the application runs in the same manner.
- using System;
- using System.Collections.Generic;
- using System.Text;
-
- namespace InterviewQuestionPart7
- {
- class Program
- {
- static void Main(string[] args)
- {
-
- CorporateCustomer cc = new CorporateCustomer();
- Console.WriteLine(cc.ID);
-
- SavingsCustomer sc = new SavingsCustomer();
- Console.WriteLine(sc.ID);
-
- }
- public abstract class Customer
-
- {
- protected Customer()
- {
- this._id = Guid.NewGuid();
- }
- private Guid _id;
- public Guid ID
- {
- get
- {
- return this._id;
- }
- }
-
- }
- public class CorporateCustomer:Customer
- {
-
- }
- public class SavingsCustomer:Customer
- {
-
-
- }
- }
- }
Now we see the output as expected.