ONDotNet.com    
 Published on ONDotNet.com (http://www.ondotnet.com/)
 See this if you're having trouble printing code examples


VB.NET OOP Part 2 - Understanding Constructors

by Budi Kurniawan co-author of VB.NET Core Classes in a Nutshell
11/04/2002

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
By Budi Kurniawan, Ted Neward


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."

The Relationship With the Base Class

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.

Initialization With Constructors

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
By Jesse Liberty


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

Multiple Constructors

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")

Forcing an Object to Have a Specific Type

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.

Summary

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.