The new version of Visual Basic, VB7 and also known as VB.NET, offers the full features of an OOP language. Even though the concept of objects is not entirely new to VB programmers, writing code in an OOP way probably is. Here is an article for VB programmers who want to learn OOP and have a quick grasp of it. You also might want to check out part one of this series.
A method is either a subroutine or a function. The difference, of course, is that a function in Visual Basic returns a value, while a subroutine does not. Both functions and subroutines can accept arguments.
When choosing method names, you should, of course, use a name that reflects what the method does. But there are situations where you need methods that do similar things but accept different lists of arguments. For example, you may need a method that prints a double, as well as a method that prints a string. What do you do? You can write two methods and call them PrintDouble and PrintString respectively. But you really want to call both methods Print, because that is what they do.
OOP languages, including VB.NET, allow multiple methods to have the same name, as long as those methods have different lists of arguments. This is called method overloading. Each of the methods with the same name is comfortably called an overload. In VB.NET, you add the keyword Overloads as the first part in the method signature. The use of the Overloads keyword is optional, however; you can still have methods with the same name without using the keyword.
For example, consider Listing 14, which shows the class Calculator with two Add methods. The first overload accepts two integers and the second overload accepts two doubles.
Imports System
Class Calculator
Overloads Public Function Add(a As Integer, b As Integer) As Integer
Add = a + b
End Function
Overloads Public Function Add(a As Double, b As Double) As Double
Add = a + b
End Function
End Class
Module Module1
Public Sub Main()
Dim counter As Calculator
counter = New Calculator()
' pass two integers
Console.WriteLine(counter.Add(1, 5))
' pass two doubles
Console.WriteLine(counter.Add(1.3, 5.9))
End Sub
End Module
|
Related Reading
|
In the Main sub in the Module1 module, we instantiate a Calculator object and call the Add method twice. On the first call to the Add method, we pass two integers, 1 and 5.
' pass two integers
Console.WriteLine(counter.Add(1, 5))
On the second call, we pass two doubles, 1.3 and 5.9.
' pass two doubles
Console.WriteLine(counter.Add(1.3, 5.9))
|
| |
The smart thing is, the Common Language Runtime knows which method overload to call. The first call to the Add method returns 6, the second method returns 7.2.
Method overloading can also be found almost everywhere in the .NET Framework Class Library. Take the Console class in the System namespace as an example. This class has a method named Write that outputs the representation of a value to the console. The Write method has 18 overloads. There is one overload that accepts a Boolean, one that accepts an integer, and so on. These overloads make sure that you can pass any type of data to the Write method and the method will still work correctly.
Beginners to OOP often make the mistake of thinking that methods can be overloads if the return values are of different types. This is not the case. In order to be an overload, the method must accept a unique set of arguments. Two methods with the same name that accept the same list of arguments will not compile, even though they return different return types.
For instance, the Calculator class in Listing 15 will not compile because the two Add methods have the same set of arguments, even though the types of their return values are different.
Listing 15: Incorrect method overloading
Imports System
Class Calculator
Overloads Public Function Add(a As Integer, b As Double) As Decimal
Add = a + b
End Function
Overloads Public Function Add(a As Integer, b As Double) As Double
Add = a + b
End Function
End Class
When you compile the class, it will report the following compile error:
error BC30301: 'Public Overloads Function Add(a As Integer, b As Double) As Decimal' and 'Public Overloads Function Add(a As Integer, b As Double) As Double' differ only by return type. They cannot overload each other.
Why doesn't the compiler allow that? Because a function can be called without expecting a return value. For example, in the case of the erroneous Calculator class, if the compiler allowed that and the programmer called the Add function by passing an integer and a double like this:
Dim counter As Calculator
counter = New Calculator()
' pass two integers
counter.Add(1, 5.89)
it would not be clear which overload is being called.
|
Sometimes when you extend a base class, you may want to have a method that has the same name as the one in the base class but does something different. In VB.NET you can do this by using the keyword Overridable in front of the declaration of the method in the base class. Then, in the derived class, you use the keyword Overrides in front of the method with the same name. This technique is called method overriding.
For example, Listing 16 shows a class called Employee with a method called Work. The method is declared overridable, meaning that the method can be overridden in the inheriting classes.
Listing 16: An overridable method
Imports System
Class Employee
Overridable Public Sub Work()
Console.Write("I am an employee.")
End Sub
End Class
The code in Listing 17 is a class called Manager that extends the class Employee in Listing 16. In the Manager class, we provide a different implementation for the method Work.
Listing 17: Method overriding
Class Manager: Inherits Employee
Overrides Public Sub Work()
Console.Write("I am a manager.")
End Sub
End Class
You can make a method not overridable by using the keyword NotOverridable. For example, the Work method in the Employee class in Listing 18 cannot be overridden.
Listing 18: Not overridable method
Imports System
Class Employee
NotOverridable Public Sub Work()
Console.Write("I am an employee.")
End Sub
End Class
In some cases, you don't know how to write the implementation of a method in a class at the time of writing the class. Implementation can only be provided by the inheriting class. Or, you know that the method will be overridden in the child classes, so why bother providing an implementation at all? If this is the case, your class is incomplete; this is called an abstract class. The method that you don't provide implementation for is called an abstract method. An abstract method is denoted by the MustOverride keyword. The class itself has the MustInherit modifier because it cannot be instantiated using the New keyword.
For example, the class in Listing 19 is named Shape and it is abstract because one of the methods (Draw) does not have implementation. Other than that, the class looks like a normal class.
Listing 19: An abstract class
Imports System
MustInherit Class Shape
Public x As Integer = 9
Public y As Integer = 0
MustOverride Sub Draw()
Public Function GetInfo() As String
GetInfo = "An abstract class"
End Function
End Class
Note that the Draw method does not have the End Sub declaration.
When you extend an abstract class, you must provide implementations for all methods that must be overridden. Otherwise, the inheriting class itself will be an abstract class and must be declared with the MustInherit keyword.
The Rectangle and Line classes in Listing 20 inherit Shape.
Listing 20: Inheriting from an abstract class
Class Rectangle: Inherits Shape
Overrides Sub Draw()
' Draw a rectangle here
End Sub
End Class
Class Line: Inherits Shape
Overrides Sub Draw()
' Draw a line here
End Sub
End Class
For beginners, interfaces are probably not very clear. Why would you want to use an interface at all? An interface defines a contract that classes must adhere to.
An interface is like an abstract class. An abstract class can have methods with or without implementations; however, an interface can only have methods that don't have implementation. In an OOP language that supports only single class inheritance like VB.NET, inheritance plays a very important role. Interfaces enable multiple inheritance in VB.NET because a VB.NET class can extend multiple interfaces. Extending an interface has a special term: implement. To implement an interface in VB.NET, you use the keyword Implements. As with extending an abstract class, you must provide implementations for all methods in the interface you implement. Otherwise, you must make your class abstract.
An interface is declared using the keyword Interface. Like other types in VB.NET, there is a naming convention for interfaces. The recommendation is to use the class's naming convention and prefix the interface name with an I. For example, here are some good names for interfaces: IScalable, ISerializable, I3DShape, IPolygonShape, etc.
For example, Listing 21 presents an interface called IShape.
Listing 21: An interface called IShape
Interface IShape
End Interface
For a class to implement an interface, the same syntax as class extension is used. In the code in Listing 22, the class Line implements the IShape interface.
Listing 22: Implementing an interface
Interface IShape
End Interface
Class Line: Implements IShape
End Class
An alternative syntax would be:
Interface IShape
End Interface
Class Line
Implements IShape
End Class
An interface in VB.NET can only have methods, properties and events. An interface cannot contain a field. All interface members are implicitly public and may not specify an access modifier. In the class that implements an interface, each method implementation must specify the interface method that it implements using the keyword Implements, followed by the name of the interface and the method name. The interface name and the method name are separated using a period.
For example, the code in Listing 23 shows an interface called IShape with one method called Draw. There is also a class named Line that implements IShape.
Listing 23: Implementing an interface method
Imports System
Interface IShape
Sub Draw()
End Interface
Class Line
Implements IShape
Sub Draw() Implements IShape.Draw
Console.Write("Draw a line")
End Sub
End Class
You can then instantiate a Line object as you would a normal class. Like abstract classes, interfaces cannot be instantiated.
|
Polymorphism is probably the hardest concept to digest for those new to OOP. Indeed, polymorphism (literally means "many forms") is probably the most misunderstood term in OOP because the word has more than one meaning. For example, if you type in the word polymorphism as a search keyword in an Internet search engine, you will find out that this word is also used in biology.
In modern software engineering discipline, polymorphism is classified into universal polymorphism and ad-hoc polymorphism. Universal polymorphism is considered purer than ad-hoc polymorphism and is also called "true polymorphism." Ad-hoc polymorphism is often described as "apparent polymorphism." Universal polymorphism is subdivided into parametric polymorphism and inclusion polymorphism; and ad-hoc polymorphism can be subdivided into overloading and coercion. These polysyllabic forms of polymorphism are explained below.
This classification was put forward by Luca Cardelli (AT&T Bell Laboratories) and Peter Wegner (Brown University) in their paper, "On Understanding Types, Data Abstraction and Polymorphism" (PDF), published in Computing Surveys in 1985. This is the presently accepted definition of polymorphism. The older definition, first put forth by C. Strachey in 1967, identified only two types of polymorphism: parametric polymorphism and ad-hoc polymorphism.
In OOP, when we talk about polymorphism, it simply means "one interface, many implementations." To be more specific, the term is used to describe reference variables that may at run-time refer to objects of different classes. (Overloading is also a type of polymorphism; however, in OOP it is simply referred to as method overloading.) In other words, polymorphism (as far as OOP is concerned) simply means that you can assign to an object reference an object whose type is different from the object reference. In essence, if you have an object reference a whose type is A, it is legal to assign and object of type B, as in the following.
Dim a As A
a = New B()
However, B must be derived from A either directly or indirectly, or A must be an interface that is implemented by B or the class that B extends directly or indirectly.
Consider the example in Listing 24.
Listing 24: An example of polymorphism
Class Employee
Public Overridable Sub Work
System.Console.WriteLine( "I am an employee." )
End Sub
End Class
Class Manager : Inherits Employee
Public Sub Manage
System.Console.WriteLine("Managing ...")
End Sub
Public Overrides Sub Work
System.Console.WriteLine( "I am a manager" )
End Sub
End Class
Module ModMain
Sub Main()
Dim employee As Employee
employee = New Manager
employee.Work
End Sub
End Module
The example has two classes: Employee and Manager. Employee has a method called Sub and Manager extends the class Employee and adds a new method called Manage.
The Main sub in the module defines an object variable called employee of type Employee.
Dim employee As Employee
However, employee is assigned an object of type Manager, as in
employee = New Manager
Then, when the Work method is called, guess what is written on the console? I am a manager. This means that it is the Work method of Manager class that gets called. Polymorphism in action!
But why do we declare employee as Employee in the first place? Why don't we declare employee as Manager? To ensure flexibility in cases where we don't know whether the object reference (employee) will be assigned an object of type Manager or something else. The next example will make it clearer why we use polymorphism.
Say you have a Windows application and you have a method that changes the BackColor property of a control. You want to be able to pass a Button, a Label or any control that may be used in a form. For this purpose, you write the subroutine in Listing 25.
Listing 25: The ChangeColor subroutine
Private Sub ChangeColor(_
ByVal control As System.Windows.Forms.Control, _
ByVal color As system.Drawing.Color)
control.BackColor = color
End Sub
You pass two arguments to the ChangeColor sub: a System.Windows.Forms.Control object and a System.Drawing.Color object. You know that the Control class is the parent class of all Windows controls. By declaring control as Control, polymorphism allows you to pass a Control object or any object whose class is derived from the Control class. This way, you only need one sub for all controls. Without polymorphism, you need a sub for each type of control. You would have ChangeButtonColor, ChangeLabelColor, etc
The code in Listing 26 iterates all controls in a Windows form and passes each control to the ChangeColor sub. Running this code will give all controls in the current window a blue background color.
Listing 26: Passing different controls to the ChangeColor subroutine
Dim control As System.Windows.Forms.Control
For Each control In Me.Controls
ChangeColor(control, Color.Blue)
Next
By now, you should have a much better understanding of all those cool words I presented at the beginning of the article. With this understanding, you can start to take advantage of VB.NET's complete support for object-orienting programming. Happy OOPing!
Return to the .NET DevCenter.
Copyright © 2009 O'Reilly Media, Inc.