Section 3.2. OOP Development in Visual Basic


3.2. OOP Development in Visual Basic

The .NET Framework is an OOP-rich development environment. Within that environment, Visual Basic provides access to most OOP features.

The primary OOP entity in Visual Basic is the class, but the language also supports two additional variations of this standard entity: (1) the structure, a value-type variation (always derived from System.ValueType) of the normally reference-type class, and (2) modules, a class in which all members are shared and public by default. These three primary development entities, along with a few other entities, such as enumerations, fall under the broad name of type in .NET parlance. Unless otherwise noted, all discussions of class features apply also to structures and modules.

3.2.1. Classes in Visual Basic

Most Visual Basic development establishes a one-to-one relationship between a class and a source code file. However, a single file may include multiple classes . Beginning in 2005, the code for a single class may also be split among multiple source code files by using the new Partial keyword. See the entry for that keyword in Chapter 12 for additional information on its usage.

The basic source code needed to define a class is pretty simple.

 Public Class className End Class 

Once a class is defined, it can be used by creating an instance of the class, which is what is really known as the object. (Some class members can be used without creating an instance; these "shared members" are discussed below.) Instantiating an object requires (1) a variable to hold the object and (2) the creation of the object using the New keyword. These two steps are often performed in two separate VB statements.

 Dim myInstance As SimpleClass  ' Defines the variable myInstance = New SimpleClass   ' Creates the object 

These two steps can be combined into a single statement:

 Dim myInstance As SimpleClass = New SimpleClass 

A shortcut syntax makes the instantiation even simpler:

 Dim myInstance As New SimpleClass 

3.2.2. Class Members

Visual Basic classes contain the following types of members:


Field Members

This includes member variables and constants. Enumerated data types defined within a class fall into this category.


Event Members

Events are procedures that are called automatically by the Common Language Runtime in response to some action that occurs, such as an object being created, a button being clicked, a piece of data being changed, or an object going out of scope. Events can also be manually fired through code.


Method Members

This refers to both functions and subroutines. A special method subroutine called a constructor is used to help create new instances of the class.


Property Members

Properties combine aspects of both function methods and fields. They are often used to provide access to a hidden class field through a pair of property procedures, one for updating the data and one for retrieving the current data value.


Type Members

Classes may be nested, with one class contained completely within another.

The following Person class sample illustrates all of the various member types except class nesting.

 Public Class Person    ' ----- Field Members -----    Private fullName As String    Private currentAge As Short    Public Const MaxAge As Short = 120    ' ----- Event Member -----    Public Event Testing()    ' ----- Constructor Method Members -----    Public Sub New()       ' ----- Default constructor.       fullName = "<unnamed>"    End Sub    Public Sub New(ByVal newName As String)       ' ----- Simple constructor to set an initial field.       fullName = newName    End Sub    ' ----- Method Members -----    Public Sub Test()       ' ----- Test the class-defined event.       RaiseEvent Testing()    End Sub    Public Overrides Function ToString() As String       ' ----- Returns a friendly string related to the instance.       '       NOTE: The 'Overrides' keyword will be discussed       '             later in the chapter.       Return fullName & ", Age " & currentAge    End Function    ' ----- Property Members -----    Public Property Age() As Short       ' ----- This property performs simple error checking.       Get          Return currentAge       End Get       Set(ByVal value As Short)          If (value < 0) Or (value > MaxAge) Then             Throw New System.ArgumentException( _                "Age ranges from 0 to " & MAX_AGE & ".", "Age")          Else             currentAge = value          End If       End Set    End Property    Public Property Name() As String       ' ----- This property adds no special logic; it could       '       have been a public field instead.       Get          Return fullName       End Get       Set(ByVal value As String)          fullName = value       End Set    End Property End Class 

3.2.3. Class Member Accessibility

Generally, the members of a class constitute that class's public interface. But some members may exist only for the internal use of the class instance itself. Each member of a class includes an access modifier. These special keywords indicate just how visible a particular member is to code outside of the class. Table 3-1 shows the five available access modifiers.

Table 3-1. Access Modifiers

Access modifier

Description

Public

Public members are accessible to any code that accesses an instance of the class or structure, or that has access to the module containing the member. If a class has a public member, and an instance of that class is accessed from a separate project, application, or component, the public member is fully accessible to that external code.

Protected

Protected members are accessible within the confines of a class and can be used in any code derived from that class, but they cannot be accessed outside of the class. Protected members only apply to classes; they are not available to structures or modules.

Friend

Friend members are accessible anywhere within the assembly, but no further. Instances of a class with a friend member consumed outside of the assembly hide the member from that external code. Friend members can be used in classes, structures, and modules.

Protected Friend

Using Protected and Friend together grants a member all the benefits of both; such members are accessible within the class and all derived classes, and within the assembly, but not outside of it. Protected Friend members can be used in classes, but not in structures or modules.

Private

Private members are accessible anywhere within a class, structure, or module, but not outside. They are also hidden from the custom members of derived classes.


A class itself also has an access modifier, one of Public, Friend, or Private. Public classes can be accessed by another assembly that uses your class' assembly; Friend classes are accessible throughout your assembly, but not outside of it; and Private classes are only accessible within their "declaration context." Generally, Private is similar to Friend, but nested classes can be limited to use only within their parent class by using the Private keyword.

3.2.4. Field Members

Variables, constants, and enumerations declared inside of a class, but outside of any class member procedure, are field members. (Enumerations can also be declared outside of classes altogether.) They are simple to declare and use, as done in the Person class earlier.

 Private fullName As String Private currentAge As Short Public Const MaxAge As Short = 120 

Private field members are often used in tandem with member property procedures to provide logic-controlled access to a data field in the class.

Public field members are available through instances of your class.

 Dim onePerson As New Person MsgBox("Maximum allowed age is " & onePerson.MaxAge & ".") 

3.2.5. Event Members

Events members provide a way to tap into the event-controlled interfaces of the .NET Framework. The declaration and use of events is fully described in Chapter 8. The 2005 release of Visual Basic adds a new feature called custom events that provides more control over the lifetime of an event. This feature is also discussed in Chapter 8.

3.2.6. Method Members and Constructors

The function and sub procedures contained within your classes will generally make up the bulk of your Visual Basic application. (Procedures that intercept events are also considered method members.) Methods contain two main parts: (1) the declaration and (2) the body.

     ' ---- This is the declaration...     Public Function AgeInDogYears(sourceAge As Decimal) As Decimal        ' ----- ...and this is the body.        Return sourceAge * 7@     End Function 

The declaration of a method is often referred to as its signature. The signature includes the specific argument list and the return value; the method name is not part of the signature.

Private methods can only be called within the class itself. Public members can be used within your class or by external users of the class.

    ' ----- This code resides outside of the class that defines    '       the AgeInDogYears function.    Dim meAsFido As Decimal    meAsFido = theDog.AgeInDogYears(38@) 

When an object of a particular class is created, the compiler calls a special procedure within the class called a constructor or instance constructor. Constructors initialize an object when necessary. (Constructors take the place of the Class_Initialize event in pre-.NET versions of VB.)

Constructor procedures always have a name of New; more than one New procedure may appear in your class, provided each one has a different argument signature. (Normally when two procedures with the same name appear in a class, the Overloads keyworddescribed later in this chaptermust be added to each declaration. However the New procedure is a special case; it does not require the Overloads keyword.)

For classes that require no special initialization of their public or private members , the constructor can be omitted from the class; Visual Basic will provide a default constructor when no defined constructor exists in a class. But many classes require some basic initialization, and the constructor is the place to do it. The Person class defined earlier includes two constructors.

    Public Sub New()       ' ----- Default constructor.       fullName = "<unnamed>"    End Sub    Public Sub New(ByVal newName As String)       ' ----- Simple constructor to set an initial field.       fullName = newName    End Sub 

The first constructor is the default constructor; since it includes no arguments in its declaration signature, it is used by default when an instance is created that lacks any initialization arguments. The second constructor is a custom constructor; it is called when an instance is created that passes a single string argument.

    ' ----- Uses the default constructor.    Dim byDefault As Person = New Person    ' ----- Uses the custom constructor.    Dim byCustom As Person = New Person("John Q. Public") 

The arguments included in the instance declaration must match one of the constructor signatures as declared in the class.

If a class lacks any constructors, a default constructor is added automatically that does nothing beyond instantiating an object. If you want to force the class to be created with a custom constructor only, add at least one custom constructor to the class.

3.2.7. Property Members

Consider the following simple class.

     Public Class AnotherPerson        Public Name As String        Public Age As Short     End Class 

This class includes some of the functionality of the Person class defined earlier. However, the Age property has some problems. Because it is a simple public field, any instance of the class can have its Age field set to any Short value, whether 25, 87, 3349, or -23. Some of these ages are certainly invalid. How do you keep the user from setting the Age field to an invalid value?

While you could add specialized function members to set and retrieve the age, .NET includes properties that provide a more elegant solution. Within the class, properties look just like specialized functions; to the user of a class, they look like fields. (When a Visual Basic application is compiled, properties actually become method members.) The Person class defined earlier includes a more protected Age property.

     Private currentAge As Short     ...and later...     Public Property Age() As Short        Get          Return currentAge        End Get        Set(ByVal value As Short)          If (value < 0) Or (value > MaxAge) Then              Throw New System.ArgumentException( _                "Age ranges from 0 to " & MAX_AGE & ".", "Age")          Else             currentAge = value          End If     End Set End Property 

The property procedure includes two distinct property accessors, one for setting the hidden tandem value (the Set procedure) and one for retrieving the current value (the Get procedure). You can create a read-only property by supplying only the Get component and adding the ReadOnly keyword to the property definition.

     Public ReadOnly Property Age() As Short        Get          Return currentAge        End Get     End Property 

The WriteOnly keyword allows you to similarly define a property with only a Set component.

New in 2005. The 2005 release of Visual Basic allows you to specify different access levels (such as Public and Friend) to the Get and Set accessors.

3.2.8. Type Members

Classes may include nested classes as needed.

     Public Class Level1Class        Private Class Level2Class           ' ----- Add level 2 class code here.        End Class        ' ----- Add other level 1 class code here.     End Class 

If the nested class is private, it will only be accessible within the outer class.

3.2.9. Instance Members Versus Shared Members

Members of a class can either be instance members or shared members. Instance members are only useful in a specific instance of the class, that is, from an object. Until an instance of the object exists, these members cannot be used or referenced in any way. Instance members belong to specific instances of the class instead of to the class as a whole. The members added to the sample Person class above are all instance members.

     Public Class SimpleClass        ' ----- This is an instance member.        Public Comment As String     End Class     ...     ' ----- In some other code.     Dim myInstnace = New SimpleClass    myInstance.Comment = "I am not shared!" 

Shared members (sometimes called static members) can be accessed without the presence of any particular instance of the class. They belong to the whole class, but they are also "shared" among all instances of the class. Shared members are accessed by qualifying the name of the member with the name of the class.

     Public Class SimpleClass        ' ----- This is an instance member.        Public Shared Comment As String       End Class       ...       ' ----- In some other code.       SimpleClass.Comment = "I am shared!" 

All members of a Module are automatically shared, even though the Shared keyword is not used on each member of the module.

Consider a class that keeps track of how many instances of itself have been created.

     Public Class Tracker        ' ----- Shared variables can be private.        Private Shared totalInstances As Integer        Public Sub New()           ' ----- Each constructor call increments the total.           totalInstances += 1        End Sub        Public Shared Function GetInstanceCount() As Integer           ' ----- Provide read-only access to the count.           Return totalInstances        End Function        Protected Overrides Sub Finalize()           ' ----- Decrement the count in the destructor.           totalInstances -= 1           MyBase.Finalize        End Sub        End Class 

Code such as the following accesses the shared member:

    Dim firstUse As New Tracker    MsgBox(Tracker.GetInstanceCount())   ' --> Displays "1"    Dim secondUse As New Tracker    MsgBox(Tracker.GetInstanceCount())   ' --> Displays "2" 

This sample code does have a few issues. Although the Finalize destructor (called when an instance is destroyed, and described more fully later in this chapter) will eventually be called, there is no guarantee that it will be called in a timely manner. Even if a TRacker object goes out of scope or is specifically destroyed by setting the object variable to Nothing, the Finalize method may not be called for quite some time, and the instance count may appear to be inaccurate.

Another problem appears because Visual Basic is a multithreaded programming language. If separate threads of your application each create an instance of TRacker at the same time, their respective calls to the New constructor may overlap and produce invalid results. The .NET Framework includes classes that guard against such overlapping code. Mutexes, semaphores, and monitors can be used to manage conflicts between threads in your application. Visual Basic includes a SyncLock statement that also supports some conflict resolution between threads. This statement is described in the SyncLock Statement entry in Chapter 12.

3.2.10. Finalize, Dispose, and Garbage Collection

An instance of an object can be specifically destroyed by setting the variable that refers to the instance to Nothing.

     Dim usefulObject As New SimpleClass     ...     usefulObject = Nothing 

An object is also automatically destroyed when all variable references to that object go out of scope or otherwise cease to exist. When an object is destroyed using any of these methods, the garbage collection process begins.

The .NET Framework includes a garbage collection system that exists to accurately reclaim memory used by objects within .NET applications. When the garbage collector determines that an object is no longer needed, it automatically runs a special destructor method of the class called Finalize. However, there is no way to determine exactly when the garbage collector will call the Finalize method. It will be called at some time in the future, but it may not happen immediately. The .NET Framework uses a system called reference-tracing garbage collection, which periodically releases unused resources according to its schedule, not your program's schedule.

Finalize is a Protected method. It can be called from a class and its derived classes, but not from outside the class. (Since the Finalize destructor is automatically called by the garbage collector, a class should never call its own Finalize method directly.) If a class has a Finalize method, that method should in turn explicitly call its base class's Finalize method as well. The general syntax and format of the Finalize method is:

     Protected Overrides Sub Finalize()        ' ----- Cleanup code goes here, and then...        MyBase.Finalize()     End Sub 

(The MyBase and Overrides keywords are discussed later in this chapter.) Garbage collection is automatic, and it ensures that unused resources are always released without any specific interaction on the part of the programmer. In most cases, the programmer has no control over the garbage collection schedule; a garbage collection event may occur many minutes after you release an object. This may cause some resources to remain in use longer than necessary.

Since some classes may acquire resources that must be released immediately upon completed use of an object instance, .NET supports a "second destructor" called Dispose. Its general syntax and usage is:

     Class className        Implements IDisposable        Public Sub Dispose() Implements IDisposable.Dispose           ' ----- Immediate cleanup code goes here.        End Sub        ' ----- Other class code.     End Class 

(The Implements keyword is discussed later in this chapter.) The Dispose method is not called automatically by the .NET Framework. Any code that uses a class with a Dispose method must specifically call that method to initiate the first-level cleanup code. Still, a programmer may forget to call the Dispose method, and resources may be retained until they are fully cleaned up through the Finalize method.

3.2.11. Structures and Modules Versus Classes

In addition to classes, Visual Basic also supports "structures " and "modules ." (These are somewhat analogous to the VB 6 "Type" and "code module" features.) These two types are really just classes with syntax rules and default behaviors that differ somewhat from standard classes.

Structures implement instances of a value type and always derive from System.ValueType. They can never derive from any other base class, nor can a structure be used to derive other structures or classes. The members of a structure cannot specify Protected as an access modifier. Since they are value types, structures are destroyed immediately on disuse; they do not support the Finalize destructor. However, they are lightweight and simple to use for basic data constructs. Structures, when they are not too large, experience some performance increase over equivalent classes.

     Public Structure SimpleStructure        Public Comment As String        Public TotalCost As Decimal     Public Overrides Function ToString() As String        Return Comment & ", " & Format(TotalCost, "$#,##0.00")        End Function     End Structure 

Modules are similar to classes that have the Public and Shared keyword added to every member by default (although members can be made Private as well). Since all members of a module are shared, there is no need to create an instance of the module to access the members. In fact, modules cannot be instantiated. They cannot be used to derive other modules or classes, either. Modules can contain nested classes and structures, but modules themselves cannot be nested in any other type. Modules are commonly used for common procedures and global variables that need to be accessed throughout your application.

     Friend Module GenericCode       Public Function CToF(celsius As Decimal) As Decimal          ' ----- Convert Celsius to Fahrenheit.          Return (celsius * 1.8@) + 32@       End Function     End Module 

3.2.12. Interfaces

Visual Basic implements the object-oriented concept of interfaces through the Interface keyword. Interfaces define the members of a class but not the implementation. They look a lot like classes, but without the member bodies or End constructs (such as End Sub). An interface equivalent to the Person class defined earlier in this chapter might look like the following:

     Interface IPerson        Event Testing()        Sub Test()        Property Age() As Short        Property Name() As String     End Interface 

(By convention, interfaces always begin with the uppercase letter "I.") Interfaces define the public properties, methods, and events of an abstract class. Since interfaces do not support variables, constants, or constructors, some elements of the Person class are missing from this interface definition. Also, since all members of an interface are public by definition, the Public keyword is not needed on each member.

Classes implement one or more interfaces through the Implements keyword. This keyword is used in two contexts within the class: (1) at the beginning of the class to declare which interface(s) will be used in the class, and (2) attached to each member that implements a specific member of an interface. Consider the following code.

     Interface IDog        Sub Bark()        Sub ScratchFleas()     End Interface     Interface ICat     Sub Meow()       Sub DestroyFurniture()     End Interface    Class MixedUpAnimal       Implements IDog       Implements ICat       Public Sub ScratchFleas() Implements IDog.ScratchFleas          ' ----- Add code here.       End Sub       Public Sub MakeNoise() Implements IDog.Bark, ICat.Meow          ' ----- Add code here.       End Sub       Public Sub Redecorate() Implements ICat.DestroyFurniture          ' ----- Add code here.       End Sub       Public Sub ShowOff()          ' ----- Add code here.       End Sub    End Class 

This code displays various aspects of interface usage.

  • A class declares its intention to use an interface immediately, through distinct Implements statementsone for each interface to be used.

  • A class may implement multiple interfaces at once.

  • When a class implements an interface, it must implement all members of the interface, not just some.

  • Specific members of an interface are implemented through standard class members, each decorated with a separate Implements keyword followed by the name of the interface and member, as in Implements IDog.ScratchFleas. The implementation's signature must match the interface member's signature.

  • A single class member may implement multiple interface members, as long as those members share the same signature with the class member. Each interface member is added to the Implements keyword, separated by commas, as in Implements IDog.Bark, ICat.Meow.

  • The class member implementing an instance member may use the same name as the interface member, but it does not have to. The association between a class member and an interface member occurs through the Implements keyword, not through the class member name.

  • A class may implement its own members, fully unrelated to any interface members implemented in the class, as is done with the ShowOff procedure in the sample.

While the MixedUpAnimal class implements two distinct interfaces, the term interface also describes the complete set of all public members exposed by this class. This dual use of "interface" is generally not a problem, since when discussing the implementation of a specific interface, the name of that interface is usually included in the discussion.

3.2.13. Inheritance

Visual Basic implements OOP inheritance through the Inherits keyword. When a class inherits from a base class, it takes on all public and protected members of that base class; in a way, the derived class is a real implementation of the base class.

As an example of inheritance, consider a simple Employee class.

     Public Class Employee        Public FullName As String        Private currentSalary As Decimal        Public Property Salary() As Decimal           ' ----- Salary can be set directly.           Get              Return currentSalary           End Get           Set(value As Decimal)              currentSalary = value           End Set        End Property        Public Overridable Sub IncSalary(ByVal raisePercent As Decimal)           ' ----- Raises given based on a supplied percentage.           '       The percent should appear as a decimal percentage,           '       as in 0.03 for a 3% raise.           currentSalary *= 1@ + raisePercent        End Sub     End Class 

This class can be used immediately to manage employee names and salaries. But there may be special salary-related circumstances that apply to specific categories of employees. In this example, all salary increases given to executives include an additional 5 percent increase for a car allowance; secretaries receive an additional 2 percent for an overtime allowance. While distinct classes could be used, inheritance allows all of the classes to still be instances of the Employee class, despite their derived differences.

The IncSalary member in the Employee class includes the Overridable keyword. This keyword allows a derived class to modify the implementation of the base class' member. Here are the definitions for the derived Executive and Secretary classes, each of which overrides the base IncSalary member.

     Public Class Executive        Inherits Employee        Public Overrides Sub IncSalary(ByVal raisePercent As Decimal)           ' ----- Extra 5% for car allowance.           Me.Salary *= 1.05@ + raisePercent        End Sub     End Class     Public Class Secretary        Inherits Employee     Public Overrides Sub IncSalary(ByVal raisePercent As Decimal)        ' ----- Extra 2% for overtime allowance.        Me.Salary *= 1.02@ + raisePercent      End Sub   End Class 

The Me keyword will be discussed in more detail below, but in the code it means, "I'm trying to access members of the current class"in this case, either the Executive or the Secretary class. Since the currentSalary member is private to the Employee class, it can't be accessed directly by the derived classes; all access is made through the public Salary property.

Both derived classes include the statement Inherits Employee, which sets up the inheritance relationship from Employee (the base class) to either Executive or Secretary (the derived classes).

Each derived instance of the IncSalary class includes the Overrides keyword, which states that this member is specifically overriding an overridable member of the base class. A derived class is not required to override an Overridable member, but it may.

Each of these classes can now be used in code, and Visual Basic will call the appropriate class member.

     Dim worker As New Employee     Dim typist As New Secretary     Dim ceo As New Executive     ' ----- Set the initial salaries.     worker.Salary = 30000     typist.Salary = 40000     ceo.Salary = 50000     ' ----- Give everyone a 5% raise.     worker.IncSalary(0.05@)     typist.IncSalary(0.05@)     ceo.IncSalary(0.05@)     ' ----- Display the new salaries.     MsgBox(worker.Salary)   ' --> Displays 31500, a 5% increase     MsgBox(typist.Salary)   ' --> Displays 42800, a 7% increase     MsgBox(ceo.Salary)      ' --> Displays 55000, a 10% increase 

The derived classes each have access to all public members of the base class.

     ceo.FullName = "Bill Fences" 

Suppose that, in a more complete employee model, there is a derived class for every type of employee. If each of these derived classes implements its own version of IncSalary, then there is no need for any logic to exist in the IncSalary method of the base Employee class. The code could simply leave the Employee.IncSalary method empty. Visual Basic also allows you to define an abstract member, a member that has no implementation, only a definition (sort of a single-member interface). Each derived class must implement this member to be valid, so VB includes a MustOverride keyword for this purpose.

     Public MustInherit Class Employee        ' ---- Define other members, then...        Public MustOverride Sub IncSalary(ByVal raisePercent As Decimal)      End Class 

Members added with the MustOverride keyword do not include a body or an end marker (End Sub, in this case). Visual Basic does not allow a class instance to exist with any abstract members; this semiabstract Employee class can no longer be used to create instances directly. The class can only be used to derive other classes. To state this clearly, the class itself is decorated with the MustInherit keyword.

Any class that contains at least one abstract member is termed an abstract class. There may be situations where all members of a class need to be abstract. Such a class (called a pure abstract class) defines an interface, although it is not a true Visual Basic Interface.

Consider a Shape class that is designed to model the general properties and actions of geometric shapes (ellipses, rectangles, trapezoids, etc.). All shapes need a Draw method, but the implementation varies, depending on the type of shape. Similarly, methods such as Rotate, translate, and Reflect would each likely require their own shape-specific logic. This Shape class can be implemented as a pure abstract class, from which distinct Ellipse, Rectangle, and other shape-specific classes derive.

     Public MustInherit Class Shape        Public MustOverride Sub Draw()        Public MustOverride Sub Rotate(ByVal degrees As Single)        Public MustOverride Sub Translate(ByVal x As Single, _           ByVal y As Single)        Public MustOverride Sub Reflect(ByVal slope As Single, _           ByVal intercept As Single)     End Class 

Classes can also be defined so that they cannot be used to create new derived classes. The NotInheritable keyword enables this restriction.

     Public NotInheritable Class UseThisOne       ...     End Class 

Non-inheritable classes may not include any abstract members. Visual Basic also includes a NotOverridable keyword that can be used to decorate individual members in a base class.

Classes can be derived at any depth. Class A can be derived into Class B, and Class B can further be derived into Class C.

Certain rules apply to the inheritance of classes:

  • Private members are never inherited.

  • Public members are inherited by all derived classes.

  • Protected members are inherited by all derived classes, as are Protected Friend members.

  • Friend members are inherited by all derived classes in the same project as the base class, but not by derived classes in another assembly or application.

3.2.14. MyBase, MyClass, and Me

When working with derived classes, there are times when references to a member may be somewhat ambiguous; a member name may exist in both the derived class and the base class. Visual Basic provides special keywords to help alleviate this ambiguity.

The MyBase keyword provides a reference to the base class from within a derived class. If you want to call a member of the base class from within a derived class, you can use the syntax:

     MyBase.MemberName 

This will resolve any ambiguity if the derived class also has a member of the same name. The MyBase keyword can also be used to create an instance of the base class through its constructor:

     MyBase.New(...) 

The MyBase keyword cannot be used to access Private members of the base class, as they are inaccessible from derived classes.

If a class is derived from a chain of base and derived classes, MyBase looks first to the closet "parent" class in the chain for a matching member (including a matching signature). If a match is not found, VB continues up the chain until the root class, which is always System.Object.

The keywords Me and MyClass both provide a reference to the local class (the class in which the current code resides), but they exhibit slight differences. Consider a class named BaseClass and another derived from it, named DerivedClass.

      Public Class BaseClass         Public Overridable Function WhereAmI() As String            Return "Base"         End Function         Public Sub ShowLocation()            MsgBox(Me.WhereAmI())            MsgBox(MyClass.WhereAmI())         End Sub      End Class      Public Class DerivedClass         Inherits BaseClass         Public Overrides Function WhereAmI() As String            Return "Derived"         End Function      End Class 

Now consider the following code that uses these classes:

    Dim firstTry As New BaseClass    Dim secondTry As New DerivedClass    Dim useAsBase As BaseClass    useAsBase = firstTry    useAsBase.ShowLocation()  ' --> Shows "Base", "Base"    useAsBase = secondTry    useAsBase.ShowLocation()  ' --> Shows "Derived", "Base" 

The first call to ShowLocation is made using a variable of type BaseClass that refers to an object of type BaseClass. In this case, both of the calls:

     Me.WhereAmI()     MyClass.WhereAmI() 

return the same value, because they both call WhereAmI in BaseClass.

However, in the second case, the variable of type BaseClass holds a reference to an object of DerivedClass. In this case, Me refers to an object of type DerivedClass (the secondTry reference), whereas MyClass still refers to the base class BaseClass (the useAsBase reference). When using the Me keyword, the actual object as originally instantiated is used; when using MyClass, the class of the variable that is used to make the method call becomes the controlling class.

3.2.15. Shadowing and Overloading Members

Visual Basic provides a few additional features that let you provide even more control over which members are used in your base and derived classes.

3.2.15.1. Shadowing

Shadowing is similar to overriding, but with some very important differences. Consider two classes, BaseClass and DerivedClass:

     Public Class BaseClass        Public simpleField As Integer = 1        Public Overridable Sub TestOverride()           MsgBox("BaseClass:TestOverride")        End Sub       Public Sub TestShadow()           MsgBox("BaseClass:TestShadow")       End Sub     End Class     Public Class DerivedClass        Inherits BaseClass        Public Shadows simpleField As Integer = 2        Public Overrides Sub TestOverride()           MsgBox("DerivedClass:TestOverride")        End Sub        Public Shadows Sub TestShadow()           MsgBox("DerivedClass:TestShadow")        End Sub     End Class 

BaseClass has two methods, TestOverride (with the Overridable keyword) and TestShadow. DerivedClass also defines methods with the same names; in this case, TestOverride includes the Overrides keyword, and TestShadow uses the Shadows keyword. Both fields also have a related public Integer field.

The following code tests the derived class:

     Dim inUse As DerivedClass = New DerivedClass     inUse.TestOverride()     inUse.TestShadow()     MsgBox("Field = " & inUse.simpleField) 

Because the object reference inUse is to an object of DerivedClass, the calls to the TestOverride and TestShadow methods, as well as to the public variable simpleField, all refer to code in DerivedClass; the output messages are as expected:

     DerivedClass:TestOverride     DerivedClass:TestShadow     Field = 2 

The test of the classes working together, though, is a little more interesting:

     Dim inUse As BaseClass = New DerivedClass     inUse.TestOverride()     inUse.TestShadow()     MsgBox("Field = " & inUse.simpleField) 

In this case, a variable of type BaseClass refers to an object of type DerivedClass. The output this time is:

     DerivedClass:TestOverride     BaseClass:TestShadow     Field = 1 

When interacting with base and shadowed members, the type of variable used to reference the members is the deciding factor. In the sample, even though the actual object was of type DerivedClass, the fact that the variable was of type BaseClass caused VB to use the BaseClass version of shadowed features.

Class fields, such as simpleField, can only be shadowed; they cannot be overridden.

One other difference between shadowing and overriding is that a shadow element need not be the same type of element as its base class partner. For instance, the following code is valid.

     Public Class BaseClass        Public TheShadowKnows As Integer     End Class     Public Class DerivedClass        Inherits BaseClass     Public Shadows Sub TheShadowKnows()        MsgBox("This code lacks clarity!")     End Sub    End Class 

Shadowing only considers the name of the member, not its type or signature. While allowing members of different types to shadow each other seems like a hazardous practice, it actually has its use. In Visual Basic, your code can include a global variable and a local variable of the same name, but of different data types. This ability is possible because the local variable is shadowing its global namesake. In such a case, references to the variable name in the local procedure always refer to the local variable, not the global variable of the same name. This process is known as shadowing by scope.

3.2.15.2. Overloading

Overloading refers to an item being used in more than one way. Generally, overloading occurs when a class includes multiple methods with the same name but with different signatures. For instance, the Abs function in the System.Math class includes several versions, but each uses different source and return data types.

     Overloads Public Shared Function Abs(Decimal) As Decimal     Overloads Public Shared Function Abs(Double) As Double     Overloads Public Shared Function Abs(Int16) As Int16     Overloads Public Shared Function Abs(Int32) As Int32     Overloads Public Shared Function Abs(Int64) As Int64     Overloads Public Shared Function Abs(SByte) As SByte     Overloads Public Shared Function Abs(Single) As Single 

Each entry includes the Overloads keyword, which tells VB that this function is overloaded. You can create your own overloaded methods. Consider a function that retrieves a current account balance. The account could be identified either by the customer's account number or driver's license number. The method that retrieves the balance might be defined with two different signatures.

     Overloads Function GetBalance(accountNumber As Long) As Decimal     Overloads Function GetBalance(licenseNumber As String) As Decimal 

When calling GetBalance, VB decides which version to use based on whether the method is passed a string or a long integer value.

New in 2005. The 2005 release of Visual Basic introduced operator overloading to the language. This feature allows a class to define functionality for the standard VB operators, such as the addition operator (+). Operator overloading is discussed in full in Chapter 5.




Visual Basic 2005(c) In a Nutshell
Visual Basic 2005 in a Nutshell (In a Nutshell (OReilly))
ISBN: 059610152X
EAN: 2147483647
Year: 2004
Pages: 712

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