Chapter 16: Classes and Structures


A variable holds a single value. It may be a simple value such as an Integer or String, or a reference that points to a more complex entity. Two kinds of more complex entities are classes and structures.

Classes and structures are both container types. They group several related data values into a convenient package that you can manipulate as a group.

For example, an EmployeeInfo structure might contain fields that hold information about an employee (such as first name, last name, employee ID, office number, extension, and so on). If you make an EmployeeInfo structure and fill it with the data for a particular employee, you can then move the structure around as a single unit instead of passing around a bunch of separate variables holding the first name, last name, and the rest.

This chapter explains how to declare classes and structures, and how to create instances of them (instantiate them). It also explains the differences between classes and structures and provides some advice about which to use under different circumstances.

Classes

A class packages data and related behavior. For example, a WorkOrder class might store data describing a customer’s work order in its properties. It could contain methods (subroutines and functions) for manipulating the work order. It might provide methods for scheduling the work, modifying the order’s requirements, and setting the order’s priority.

Here is the syntax for declaring a class:

   [attribute_list] [Partial] [accessibility] [Shadows] [inheritance] _ Class name[(Of type_list)]     [Inherits parent_class]     [Implements interface]     statements End Class 

The only things that all class declarations must include are the Class clause and the End Class statement. Everything else is optional. The following code describes a valid (albeit not very interesting) class:

  Class EmptyClass End Class 

The following sections describe the pieces of the general declaration in detail.

attribute_list

The optional attribute_list is a comma-separated list of attributes that apply to the class. An attribute further refines the definition of a class to give more information to the compiler and the runtime system.

Attributes are rather specialized. They address issues that arise when you perform very specific programming tasks. For example, if your application must use drag-and-drop support to copy instances of the class from one application to another, you must mark the class as serializable, as shown in the following code:

  <Serializable()> _ Class Employee     Public FirstName As String     Public LastName As String End Class 

Some attributes are particular to specific kinds of classes. For example, the DefaultEvent attribute gives the form designer extra information about component classes. If you double-click on a component on a form, the code designer opens to the component’s default event.

Because attributes are so specialized, they are not described in more detail here. For more information, see the sections in the online help that are related to the tasks you need to perform.

For more information on attributes, see the “Attributes” section of the Visual Basic Language Reference or go to http://msdn.microsoft.com/library/en-us/vbls7/html/vblrfVBSpec4_10.asp. For a list of attributes defined by Visual Basic, search the online help for “Attribute Hierarchy” or go to http://msdn.microsoft.com/library/en-us/cpref/html/frlrfsystemattributeclasshierarchy.asp.

Partial

The Partial keyword tells Visual Basic that the current declaration defines only part of the class. The following code shows the Employee class broken into two pieces:

  Partial Public Class Employee     Public FirstName As String     Public LastName As String     ... End Class ... other code, possibly unrelated to the Employee class ... Partial Public Class Employee     Public Email As String     ... End Class  

The program could contain any number of other pieces of the Employee class, possibly in different code modules. At compile time, Visual Basic finds these pieces and combines them to define the class.

One of the primary benefits of classes is that they hold the code and data associated with the class together in a nice package. Scattering the pieces of a class in this way makes the package less self-contained and may lead to confusion. To prevent confusion, you should avoid splitting a class unless you have a good reason to (for example, to allow different developers to work on different pieces of the class at the same time).

At least one of the pieces of the class must be declared with the Partial keyword, but in the other pieces it is optional. Explicitly providing the keyword in all of the class’s partial definitions emphasizes the fact that the class is broken into pieces and may minimize confusion.

accessibility

A class’s accessibility clause can take one of the following values: Public, Protected, Friend, Protected Friend, or Private.

Public indicates that the class should be available to all code inside or outside of the class’s module. This enables the most access to the class. Any code can create and manipulate instances of the class.

You can only use the Protected keyword if the class you are declaring is contained inside another class. For example, the following code defines an Employee class that contains a protected EmployeeAddress class:

  Public Class Employee     Public FirstName As String     Public LastName As String     Protected Address As EmployeeAddress     Protected Class EmployeeAddress         Public Street As String         Public City As String         Public State As String         Public Zip As String     End Class     ... other code ... End Class  

Because the EmployeeAddress class is declared with the Protected keyword, it is only visible within the enclosing Employee class and any derived classes. For example, if the Manager class inherits from the Employee class, code within the Manager class can access the Address variable.

The Friend keyword indicates that the class should be available to all code inside or outside of the class’s module within the same project. The difference between this and Public is that Public allows code outside of the project to access the class. This is generally only an issue for code libraries (.dll files) and control libraries. For example, suppose that you build a code library containing dozens of routines and then you write a program that uses the library. If the library declares a class with the Public keyword, the code in the library and the code in the main program can use the class. On the other hand, if the library declares a class with the Friend keyword, only the code in the library can access the class, not the code in the main program.

Protected Friend is the union of the Protected and Friend keywords. A class declared Protected Friend is accessible only to code within the enclosing class or a derived class and only within the same project.

A class declared Private is accessible only to code in the enclosing module, class, or structure. If the EmployeeAddress class were declared Private, only code within the Employee class could use that class.

If you do not specify an accessibility level, it defaults to Friend.

Shadows

The Shadows keyword indicates that the class hides the definition of some other entity in the enclosing class’s base class.

The following code shows an Employee class that declares a public class OfficeInfo and defines an instance of that class named Office. The derived class Manager inherits from Employee. It declares a new version of the OfficeInfo class with the Shadows keyword. It defines an instance of this class named ManagerOffice.

  Public Class Employee     Public Class OfficeInfo         Public OfficeNumber As String         Public Extension As String     End Class     Public FirstName As String     Public LastName As String     Public Office As New OfficeInfo End Class Public Class Manager     Inherits Employee     Public Shadows Class OfficeInfo         Public OfficeNumber As String         Public Extension As String         Public SecretaryOfficeNumber As String         Public SecretaryExtension As String     End Class     Public ManagerOffice As New OfficeInfo End Class  

The following code uses the Employee and Manager classes. It creates instances of the two classes and sets their Office.Extension properties. Both of those values are part of the Employee class’s version of the OfficeInfo class. Next, the code sets the Manager object’s ManagerOffice.SecretaryExtension value.

  Dim emp As New Employee Dim mgr As New Manager emp.Office.Extension = "1111" mgr.Office.Extension = "2222" mgr.ManagerOffice.SecretaryExtension = "3333" 

Note that the Manager class contains two different objects of type OfficeInfo. Its Office property is the Employee class’s flavor of OfficeInfo class. Its ManagerOffice value is the Manager class’s version of OfficeInfo.

The presence of these different classes with the same name can be confusing. Usually, you are better off not using the Shadows keyword in the declarations and giving the classes different names. In this case, you could call the Manager class’s included class ManagerOfficeInfo.

It is more common to use the Shadows keyword to allow the derived class to replace a method in the parent class.

inheritance

A class’s inheritance clause can take the value MustInherit or NotInheritable.

MustInherit prohibits the program from creating instances of the class. The program should create an instance of a derived class instead. This kind of class is sometimes called an abstract class.

By using MustInherit, you can make a parent class that defines some of the behavior that should be implemented by derived classes without implementing the functionality itself. The parent class is not intended to be used itself, just to help define the children.

For example, the following code defines the Vehicle class with the MustInherit keyword. This class defines features that are common to all vehicles. It defines a NumWheels variable and a Drive subroutine declared with the MustOverride keyword. The real world doesn’t contain generic vehicles, however. Instead, it contains cars, trucks, and other specific kinds of vehicles. The code defines a Car class that inherits from the Vehicle class. When you enter the Inherits statement and press Enter, Visual Basic automatically adds the empty Drive subroutine required by the Vehicle class.

  Public MustInherit Class Vehicle     Public NumWheels As Integer     Public MustOverride Sub Drive() End Class Public Class Car     Inherits Vehicle     Public Overrides Sub Drive()     End Sub End Class  

The following code uses these classes. It declares a Vehicle and a Car variable. The first assignment statement causes an error because it tries to make a new Vehicle object. This is not allowed, because Vehicle is declared with the MustInherit keyword. The program sets variable a_car to a new Car variable and then sets variable a_vehicle to a_car. This works because a Car is a type of Vehicle, so the a_vehicle variable can refer to a Car object. This lets the program handle different kinds of vehicles (Cars, Trucks, BigRigs) using the generic Vehicle type if that is convenient. In its last line, the code assigns a_vehicle directly to a new Car object.

  Dim a_vehicle As Vehicle Dim a_car As Car a_vehicle = New vehicle    ' This causes an error because Vehicle is MustInherit. a_car = New Car            ' This works. a_vehicle = a_car          ' This works. a_vehicle = New Car        ' This works. 

The NotInheritable keyword does the opposite of the MustInherit keyword. MustInherit says that a class must be inherited to be instantiated. NotInheritable says no class can inherit from this one.

You can use NotInheritable to stop other developers from making new versions of the classes you have built. This isn’t really necessary if you design a well-defined object model before you start programming and if everyone obeys it. NotInheritable can prevent unnecessary proliferation of classes if developers don’t pay attention, however. For example, declaring the Car class NotInheritable would prevent overeager developers from deriving FrontWheelDriveCar, RedCar, and Subaru classes from the Car class.

Of type_list

The Of type_list clause makes the class generic. It allows the program to create instances of the class that work with specific data types. For example, the following code defines a generic Tree class. The class includes a public variable named RootObject that has the data type given in the class’s Of data_type clause.

  Public Class Tree(Of data_type)     Public RootObject As data_type     ... End Class 

When you read this declaration, you should think “Tree of something,” where something is defined later when you make an instance of the class.

The following code fragment declares the variable my_tree to be a “Tree of Employee.” It then instantiates my_tree and sets its RootObject variable to an Employee object.

  Dim my_tree As Tree(Of Employee) my_tree = New Tree(Of Employee) my_tree.RootObject = New Employee ... 

Chapter 19 discusses generic classes further.

Inherits parent_class

The Inherits statement indicates that the class (the child class) is derived from another class (the parent class). The child class automatically inherits the parent’s properties, methods, and events.

The following code defines an Employee class that contains LastName, FirstName, OfficeNumber, and Extension variables. It then derives the Manager class from the Employee class. Because it inherits from the Employee class, the Manager class automatically has LastName, FirstName, OfficeNumber, and Extension variables. It also adds new SecretaryOfficeNumber and SecretaryExtension variables. These are available to instances of the Manager class but not to the Employee class.

  Public Class Employee     Public FirstName As String     Public LastName As String     Public OfficeNumber As String     Public Extension As String End Class Public Class Manager     Inherits Employee     Public SecretaryOfficeNumber As String     Public SecretaryExtension As String End Class  

The following code makes a new Employee object and sets its Extension property to 1000. It then creates a Manager object and sets its Extension and SecretaryExtension values.

  Dim emp As New Employee emp.Extension = "1000" Dim mgr As New Manager mgr.Extension = "2000" mgr.SecretaryExtension = "2001" 

If a class inherits from another class, the Inherits statement must be the first statement after the Class statement that is not blank or a comment. Also note that a class can inherit from at most one parent class, so a class definition can include at most one Inherits statement.

For more information on inheritance, see the Chapter 15.

Implements interface

The Implements keyword indicates that a class will implement an interface. An interface defines behaviors that the implementing class must provide, but it does not provide any implementation for the behaviors.

For example, the following code defines the IDomicile interface. By convention, the names of interfaces should begin with the capital letter I. This interface defines the SquareFeet, NumBedrooms, and NumBathrooms properties, and the Clean subroutine.

The interface also defines the read-only property FileSystemNeeded. Usually a read-only property calculates its return from other property values. For example, FileSystemNeeded might return True if a house has more than a certain number of square feet. You can define write-only properties similarly, although they are much less common than read-only properties.

The House class implements the IDomicile interface. When you type the Implements statement and press Enter, Visual Basic automatically generates empty routines to provide the features defined by the interface.

  Public Interface IDomicile     Property SquareFeet() As Integer     Property NumBedrooms() As Integer     Property NumBathrooms() As Integer     ReadOnly Property NeedsFireSystem() As Boolean     Sub Clean() End Interface Public Class House     Implements IDomicile     Public Sub Clean() Implements IDomicile.Clean     End Sub     Public Property NumBathrooms() As Integer Implements IDomicile.NumBathrooms         Get         End Get         Set(ByVal Value As Integer)         End Set     End Property     Public Property NumBedrooms() As Integer Implements IDomicile.NumBedrooms         Get         End Get         Set(ByVal Value As Integer)         End Set     End Property     Public Property SquareFeet() As Integer Implements IDomicile.SquareFeet         Get         End Get         Set(ByVal Value As Integer)         End Set     End Property     Public ReadOnly Property NeedsFireSystem() As Boolean _      Implements IDomicile.NeedsFireSystem         Get         End Get     End Property End Class  

An interface defines behaviors but does not supply them. When you derive a class from a parent class, the derived class inherits all the code that the parent class uses to implement its features. When you implement an interface, the behavior is defined, but not supplied for you. That makes interfaces more difficult to use than inheritance, so inheritance is generally preferred whenever it is possible.

One case where the inheritance of Visual Basic is insufficient is when you need to implement multiple inheritance. In multiple inheritance, one child class can inherit from more than one parent class. For example, you might define a Domicile class and a Boat class, and then make the HouseBoat class inherit from both. You can do this in some languages but not in Visual Basic. However, you can make a class implement more than one interface.

The following code defines the IBoat interface. It then defines the HouseBoat class and uses two Implements statements to indicate that it implements both the IDomicile and IBoat interfaces.

  Public Interface IBoat     Property HasMotor() As Boolean     Property HorsePower() As Integer     Property Capacity() As Integer     Sub Sail() End Interface Public Class HouseBoat     Implements IDomicile     Implements IBoat     Public Sub Clean() Implements IDomicile.Clean     End Sub     Public ReadOnly Property NeedsFireSystem() As Boolean Implements  IDomicile.NeedsFireSystem         Get         End Get     End Property     Public Property NumBathrooms() As Integer Implements IDomicile.NumBathrooms         Get         End Get         Set(ByVal Value As Integer)         End Set     End Property     Public Property NumBedrooms() As Integer Implements IDomicile.NumBedrooms         Get         End Get         Set(ByVal Value As Integer)         End Set     End Property     Public Property SquareFeet() As Integer Implements IDomicile.SquareFeet         Get         End Get         Set(ByVal Value As Integer)         End Set     End Property     Public Property Capacity() As Integer Implements IBoat.Capacity         Get         End Get         Set(ByVal Value As Integer)         End Set     End Property     Public Property HasMotor() As Boolean Implements IBoat.HasMotor         Get         End Get         Set(ByVal Value As Boolean)         End Set     End Property     Public Property HorsePower() As Integer Implements IBoat.HorsePower         Get         End Get         Set(ByVal Value As Integer)         End Set     End Property     Public Sub Sail() Implements IBoat.Sail     End Sub End Class  

Using an interface in place of inheritance is sometimes called interface inheritance. The class doesn’t inherit a parent class’s code, but it does inherit the definition of the features that it must provide.

Note that a class can inherit from one class and also implement one or more interfaces. To save coding, you could make one of the parent interfaces into a class. For example, if the IDomicile interface defines more behaviors than the IBoat interface, and if those behaviors are generic enough to provide help for derived classes, you could turn IDomicile into a Domicile class that implemented those features. Then the House and HouseBoat classes could inherit the Domicile class’s features, and HouseBoat would implement IBoat.

If a class declaration uses any Implements statements, they must come after any Inherits statement and before any other statements (other than comments).




Visual Basic 2005 with  .NET 3.0 Programmer's Reference
Visual Basic 2005 with .NET 3.0 Programmer's Reference
ISBN: 470137053
EAN: N/A
Year: 2007
Pages: 417

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net