Beginners of OOP with VB.NET often don't pay enough attention to constructors. The reason for this is their classes are usable even without a constructor. What's worse is that many think constructors are just another type of method, which is simply not true. This article focuses on constructors, what they are used for, and some examples on using them. Understanding constructors well helps you write better classes.
For an object to be created from a class, the class needs a constructor. At a glance, a constructor looks just like a method. However, constructors are used for the sole purpose of creating an instance of a class. Here are the characteristics of a constructor:
Say you write a class called Employee, as given below:
|
Related Reading
VB.NET Core Classes in a Nutshell |
Public Class Employee
Public Sub Work()
System.Console.WriteLine("I am working.")
End Sub
End Class
You can instantiate an object of type Employee by using the New keyword like this:
Dim employee As Employee
employee = New Employee()
employee.Work()
There is nothing in the Employee class definition other than the Work method, yet you still can construct an Employee object. This seems to contradict the previous statement that you need a constructor to instantiate an object of a class. What actually happens is the VB compiler checks for the presence of a constructor in a class it compiles. If none is found, it automatically adds a no-argument constructor. Therefore, the previous Employee class is equivalent to the one below:
Public Class Employee
Public Sub New()
End Sub
Public Sub Work()
System.Console.WriteLine("I am working.")
End Sub
End Class
However, if there is a constructor, whether it accepts an argument or not, the compiler will not add a no-argument constructor. For example, if you have a class such as the one below:
Public Class Employee
Sub New(ByVal name As String)
End Sub
Public Sub Work()
System.Console.WriteLine("I am working.")
End Sub
End Class
you cannot construct an Employee object using the following code:
Dim employee As Employee
employee = New Employee()
This is because there is now no no-argument constructor in the Employee class. In VB, constructors must be declared as a Sub and in most cases they have a Public access modifier. However, a constructor can also have a Protected, Private, Friend, or the default modifier. For example, you use the Protected or Private modifier in a Singleton class to prevent the user from directly instantiating an object of that class. Singletons will be discussed in the next article, "The Singleton Design Pattern."
If a child class extends a base class, the compiler will make a call from the child class' constructor to the base class' no-argument constructor. The call will be invoked from the first statement of the child class' constructor. For example, consider the Employee class and the Manager class that extends Employee, as in the following code:
Public Class Employee
Public Sub New()
System.Console.WriteLine("Employee's constructor.")
End Sub
Public Sub Work()
System.Console.WriteLine("I am working.")
End Sub
End Class
Public Class Manager : Inherits Employee
Public Sub New()
System.Console.WriteLine("Manager's constructor.")
End Sub
End Class
When the Manager class' constructor is invoked, like in the following code, the Employee class' no-argument constructor is also called.
Dim manager As Manager
manager = New Manager()
The result on the console is as follows:
Employee's constructor.
Manager's constructor.
Note that the code in the base class' constructor is run before the code in the child class' constructor. If the base class does not have a no-argument constructor, the class won't compile. For example, the following code will produce a compile error because the Employee class (base class) does not have a no-argument constructor.
Public Class Employee
Public Sub New(ByVal name As String)
System.Console.WriteLine("Employee's constructor.")
End Sub
Public Sub Work()
System.Console.WriteLine("I am working.")
End Sub
End Class
Public Class Manager : Inherits Employee
Public Sub New()
System.Console.WriteLine("Manager's constructor.")
End Sub
End Class
This compile error occurs because the compiler adds a call to the base class' no-argument constructor's on the first line of the child class' constructor. One solution to this problem is to add a no-argument constructor to the base class. However, if you don't want to do this, you can use the MyBase keyword to reference any constructor in the base class. Note that since MyBase is present in the child class' constructor, the compiler does not add another call to the base class' no-argument constructor. The MyBase statement must be the first line in the constructor:
Public Class Employee
Public Sub New(ByVal name As String)
System.Console.WriteLine( _
"Employee's constructor with one argument.")
End Sub
Public Sub Work()
System.Console.WriteLine("I am working.")
End Sub
End Class
Public Class Manager : Inherits Employee
Public Sub New(ByVal name As String)
MyBase.New(name)
System.Console.WriteLine("Manager's constructor.")
End Sub
End Class
Constructor calls are only valid as the first statement in a constructor. Even if a class does not explicitly extend another class, you can still call the base class' constructor because every class implicitly extends the System.Object class if no class is explicitly defined as the base class. Therefore, the constructor in the Manager class below is valid:
Public Class Manager
Public Sub New(ByVal name As String)
MyBase.New()
System.Console.WriteLine("Manager's constructor.")
End Sub
End Class
Thus, MyBase.New() in the Manager class' constructor calls the System.Object
class' no-argument constructor.
|
One of the main uses of constructors is for data initialization. When you create an instance of a class using the New keyword, the compiler does some initialization in the following order:
As an example, consider the Manager class below:
|
Related Reading
Learning Visual Basic .NET |
Public Class Manager : Inherits Employee
Private id As Integer = 88
Public Sub New(ByVal name As String)
MyBase.New(name)
System.Console.WriteLine("Manager's constructor.")
End Sub
End Class
First, MyBase.New(name) will be called. Then it will initialize the id private
field with the value 88. Finally, the compiler calls the WriteLine method, as
in:
System.Console.WriteLine("Manager's constructor.")
A constructor gives the user of your class a chance to pass a value for the initialization. For example, consider the following code:
Public Class Manager : Inherits Employee
Private nameField As String
Public Sub New(ByVal name As String)
nameField = name
System.Console.WriteLine("Manager's constructor.")
End Sub
End Class
Here the nameField variable is initialized in the constructor. The user of the
class can pass a value for the nameField. For instance, here is the code to
pass "John" for the nameField variable:
Dim manager As Manager
manager = New Manager("John")
And, here is how you pass "Kevin" to the Manager object:
Dim manager As Manager
manager = New Manager("Kevin")
If a class-level variable needs to be initialized in a constructor and the constructor happens to have an argument with an identical name with the class-level variable, the argument will hide the class-level variable. To access the class-level variable from inside the constructor, use the Me keyword. For example, the following Manager class' constructor has an argument with the same name as a class-level variable, and uses the Me keyword to access the class-level variable.
Public Class Manager : Inherits Employee
Private name As String
Public Sub New(ByVal name As String)
Me.name = name
System.Console.WriteLine("Manager's constructor.")
End Sub
End Class
A class can have multiple constructors to give the user flexibility in constructing an object. For example, in the following Manager class there are two constructors. One is a no-argument constructor and one that accepts a String.
Public Class Manager
Private nameField As String
Public Sub New()
'give nameField a default value
nameField = "Tony"
End Sub
Public Sub New(ByVal name As String)
nameField = name
End Sub
End Class
Here, the user can use either constructor. If the user does not know or does not want to pass a name value, then he/she can use the no-argument constructor. Otherwise, the second constructor can be used. Even with constructors that accept different arguments, oftentimes they execute the same code. Look at the following:
Public Class Manager
Private nameField As String
Public Sub New()
'give nameField a default value
nameField = "Tony"
System.Console.WriteLine("I am the manager.")
End Sub
Public Sub New(ByVal name As String)
nameField = name
System.Console.WriteLine("I am the manager.")
End Sub
End Class
Both constructors execute the following line:
System.Console.WriteLine("I am the manager.")
And in a typical class, there could be multiple lines of code that need to be run in each of the class constructor. Having the same set of code in two or more different places is not wise, because if you need something changed, you need to update it in more than one place. A common technique is to put the code in one constructor and call that constructor from the other constructors. Now the Manager class' no-argument constructor calls the other constructor:
Public Class Manager
Private nameField As String
Public Sub New()
'default value for nameField is Tony
Me.New("Tony")
End Sub
Public Sub New(ByVal name As String)
nameField = name
System.Console.WriteLine("I am the manager.")
End Sub
End Class
Using a constructor for initialization also simplifies the code at the
client side. For example, a Manager class has two fields: name and id. You can
either let the user access the name and id fields by making those fields public
or by creating a property for each field, or you can create a constructor that
accepts two arguments. Without the constructor, the user code would be:
Dim manager As Manager
manager = New Manager()
manager.id = 77
manager.name = "Tony"
With a constructor, it would be simpler:
Dim manager As Manager
manager = New Manager(77, "Tony")
The other use of constructors is to force an object to have a specific characteristic or behavior. Consider for example the following Person class:
Public Class Person
Private age As Integer
Private male As Boolean 'true indicates a man, false a woman
End Class
Without any explicit constructor, the only constructor the Person class has is
a no-argument constructor. However, all objects constructed using the New
keyword will have its male field False, therefore indicating that the Person is
a female. Expectedly, there will be a method or property that the user can call
to set the value of the male field. If the user forgets to call this method,
however, the resulting object can have invalid values.
Using a constructor that accepts a boolean, such as in the following Person class, will solve the problem.
Public Class Person
Private age As Integer
Private male As Boolean
Public Sub New(ByVal male As Boolean)
Me.male = male
End Sub
End Class
Now the user of your class must supply a boolean for every Person object constructed. There is no way the user can forget to set this value because the only constructor the Person class has requires a boolean.
In this article, you have learned about constructors. In brief, constructors can be used for:
Budi Kurniawan is a senior J2EE architect and author.
Return to ONDotnet.com
Copyright © 2009 O'Reilly Media, Inc.