Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
(ebook) Visual Studio .NET Mastering Visual Basic.pdf
Скачиваний:
132
Добавлен:
17.08.2013
Размер:
15.38 Mб
Скачать

378 Chapter 8 BUILDING CUSTOM CLASSES

to the base class. In a drawing application, all shapes have an outline and a fill color. These properties can be implemented in the Shape class, because they apply to all derived classes. Any methods with common implementation for all classes should also be implemented as methods of the parent class.

The same techniques can be applied to more elaborate classes. For example, you can create a class that represents persons and then derive any number of classes from the Person class. The derived classes could be the Employee class, the Salesperson class, the Consultant class, and so on. The Person class stores the information that is common to all persons, and each of the derived classes inherits these properties and methods. The Pay method can’t be common to all persons, and it must be implemented in each individual class. Some persons are paid a salary, others are paid commissions, and so on. The individual methods of each class must implement the Pay method according to the type of person they represent. Inheritance pays off in very large projects, while it may introduce substantial complications in small projects, especially if used without careful design.

Object Constructors and Destructors

As you already know, objects are created and then disposed of when no longer needed. To construct an object, you must first declare it and then set it to a new instance of the class it represents. To construct a triangle, for example, you can use either of these two statements:

Dim shape1 As Triangle = New Triangle()

Dim shape1 As New Triangle()

It is also possible to specify the properties of an object in the same line that creates the object, with the New keyword. This is the object’s constructor (it initializes the object by setting some or all of its properties).

Dim rect1 As Rectangle = New Rectangle(10, 10, 50, 90)

The shapes in the Shapes class can’t be initialized in the same line that declares them, because they don’t provide a constructor. We must implement a so-called parameterized constructor, which allows you to pass arguments to an object as you declare it. These arguments are usually the basic properties of the object. Parameterized constructors don’t pass arguments for all the properties of the object; they expect only enough parameter values to make the object usable.

Constructors are implemented with the New subroutine, which is called every time a new instance of the class is initialized. This is where you code initialization tasks such as opening files and establishing connections to databases. We used the New subroutine to instantiate a new Timer object in an earlier example. This time, we’ll create a New subroutine for each shape, and we’ll declare arguments for the New subroutine.

VB6 VB.NET

The Class_Initialize method of VB6 has been replaced by the New subroutine, and the Class_Terminate method of VB6 has been replaced by the Destruct subroutine in VB.NET.

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

POLYMORPHISM 379

Let’s start with the Triangle class. When we initialize a Triangle, we want to be able to specify the sides of the triangle. Here’s the constructor for the Triangle class:

Sub New(ByVal sideA As Double, ByVal sideB As Double, ByVal sideC As Double) MyBase.New()

side1 = sideA side2 = sideB side3 = sideC

End Sub

The code is quite trivial, with the exception of the statement that calls the MyBase.New subroutine. MyBase is a keyword that lets you access the members of the base class (a topic that’s discussed in detail later in this chapter). The reason you must call the New method of the base class is that the base class may have its own constructor, which can’t be called directly. You must always insert this statement in your constructors to make sure that any initialization tasks that must be performed by the base class will not be skipped.

Likewise, when we create a Circle object, we want to be able to specify its radius. The following is the parameterized constructor of the Circle class:

Sub New(ByVal radius As Double) MyBase.New()

cRadius = radius End Sub

When you enter a statement like

Dim shape1 As New Triangle(

in the editor, you will see a list of the parameters you can set, as shown in Figure 8.11.

Figure 8.11

The members of the various Shape constructors displayed by IntelliSense

If you no longer need an object, you can set it to Nothing. The Common Language Runtime (CLR) won’t release the object as soon as you set it to Nothing. The new garbage collector (GC) checks periodically for objects that are no longer needed and releases them. However, you don’t know when this will happen. If there are tasks you want to perform prior to releasing an object, place them in the Destruct subroutine. The GC will call this subroutine (if it exists) prior to releasing the object.

The New() subroutine is usually overloaded. We always provide a constructor that accepts no arguments, so that developers can create an instance of the class without having to specify any of the arguments. The following New() constructor allows you to create an instance of the Triangle shape without passing any parameters:

Sub New()

MyBase.New()

End Sub

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

380 Chapter 8 BUILDING CUSTOM CLASSES

You may have noticed the lack of the Overloads keyword. Constructors can have multiple forms and don’t require the use of Overloads—just supply as many implementations of the New() subroutine as you need. The following statements show how to create three overloaded forms of the New constructor of the Circle shape. The first constructor accepts no arguments, the second constructor accepts the radius of the circle, and the last constructor accepts a Rectangle object that encloses the circle:

Sub New() MyBase.New()

End Sub

Sub New(ByVal radius As Double) MyBase.New()

cRadius = radius End Sub

Sub New(ByVal rect As Rectangle) MyBase.New()

cRadius = rect.Width End Sub

Instance and Shared Methods

As you may have noticed in previous chapters (and it will become even more clear in the following chapters), some classes allow you to call some of their members without first creating an instance of the class. The String class, for example, exposes the IsLeapYear method, which accepts as argument a numeric value and returns a True/False value indicating whether the year is leap or not. You can call this method through the DateTime (or Date) class, as shown in the following statement:

If DateTime.IsLeapYear(1999) Then

{ process a leap year }

End If

Other members, like the Day property, can’t be called through the name of the class. You must first create an instance of the DateTime class, assign a value to it, and then call the Day method of the specific instance of the class. The Day property returns the number of the day, and it has meaning only when applied to a specific date. To call the Day property, declare a variable of the Date type, initialize it, and then call its Day property:

Dim d1 As Date = Now()

Console.WriteLine(d1.Day)

If you attempt to call the property Date.Day, the statement will not be compiled and the error message will be “Day is not a member of Date.” The methods that don’t require that you create an instance of the class before you call them are called shared methods. Methods that can be applied to an instance of the class are called instance methods. By default, all methods are instance methods. To create a shared method, you must prefix the corresponding function declaration with the Shared keyword, just like a shared property.

Why do we need a shared method, and when should we create shared methods? If a method doesn’t apply to a specific instance of a class, make it shared. Let’s consider the DateTime class, which implements the Date data type. The DaysInMonth methods returns the number of days in

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

POLYMORPHISM 381

the month that was passed to the method as argument. You don’t really need to create an instance of a Date object to retrieve the current date, so the DaysInMonth method is a shared method. The AddDays method, on the other hand, is an instance method. We have a date to which we want to add a number days and construct a new date. In this case, it makes sense to apply the method to an instance of the class—the instance that represents the date to which we add the number of days.

The SharedMembers project on the CD is a simple class that demonstrates the differences between a shared and an instance method. Both methods do the same thing: they reverse the characters in a string. The IReverseString method is an instance method: it reverses the current instance of the class, which is a string. The SReverseString method is a shared method: it reverses its argument. Listing 8.40 shows the code that implements the SharedMembersClass component.

Listing 8.40: A Class with a Shared and an Instance Method

Public Class SharedMembersClass Private strProperty As String Sub New(ByVal str As String)

strProperty = str End Sub

Public Function IReverseString() As String Return (StrReverse(strProperty))

End Function

Public Shared Function SReverseString(ByVal str As String) As String Return (StrReverse(str))

End Function End Class

The instance method acts on the current instance of the class. This means that the class must be initialized to a string, and this is why the New constructor requires a string argument. To test the class add a form to the project, make it the Startup object and add two buttons on it. The code behind the two buttons is shown next:

Private Sub Button1_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles Button1.Click

Dim testString As String = “ABCDEFGHIJKLMNOPQRSTUVWXYZ”

Dim obj As New SharedMembersClass(testString)

Console.WriteLine(obj.IReverseString)

End Sub

Private Sub Button2_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles Button2.Click

Dim testString As String = “ABCDEFGHIJKLMNOPQRSTUVWXYZ”

Console.WriteLine(SharedMembersClass.SReverseString(testString))

End Sub

The code behind the first button creates a new instance of the SharedMembersClass and calls its IReverseString method. The second button calls the SReverseString method through the class’s name and passes the string to be reversed as argument to the method.

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com