Section 25.6. Generic Classes


25.6. Generic Classes

The concept of a data structure (e.g., a stack) that contains data elements can be understood independently of the element type it manipulates. A generic class provides a means for describing a class's capabilities in a type-independent manner. You can then instantiate type-specific objects of the generic class. This capability is an opportunity for software reusability.

Once you have a generic class, you can use a simple, concise notation to indicate the actual type(s) that should be used in place of the class's type parameter(s). At compilation time, the compiler ensures the type safety of your code, and the runtime system replaces type parameters with actual arguments to enable your client code to interact with the generic class.

One generic Stack class, for example, could be the basis for creating many Stack classes (e.g., "Stack of Double," "Stack of Integer," "Stack of Char," "Stack of Employee"). Figure 25.5 presents a generic Stack class declaration. A generic class declaration is similar to a non-generic class declaration, except that the class name is followed by a type parameter list (line 3). Type parameter E represents the element type the Stack will manipulate. As with generic methods, the type parameter list of a generic class can have one or more type parameters separated by commas. Type parameter E is used throughout the Stack class declaration (Fig. 25.5) to represent the element type. Class Stack declares variable elements as an array of type E (line 5). This array (created at line 15 or 17) will store the Stack's elements. [Note: This example implements a Stack as an array. As you have seen in Chapter 24, Data Structures, Stacks also are commonly implemented as linked lists.]

Figure 25.5. Generic class Stack declaration

  1  ' Fig. 25.5: Stack.vb  2  ' Generic class Stack  3  Public Class Stack(Of E)  4     Private top As Integer ' location of the top element  5     Private elements() As E ' array that stores Stack elements  6  7     ' parameterless constructor creates a Stack of the default size  8     Public Sub New()  9        MyClass. New(10)' default stack size 10 elements 10     End Sub ' New 11 12     ' constructor creates a Stack of the specified number of elements 13     Public Sub New(ByVal stackSize As Integer) 14        If stackSize > 0 Then ' validate stackSize 15           elements = New E(stackSize - 1) {} ' create stackSize elements 16        Else 17           elements = New E(9) {}' create 10 elements  18        End If 19 20        top = -1 ' Stack initially empty 21     End Sub' New 22 23     ' push element onto the Stack; if successful, return true 24     ' otherwise, throw FullStackException 25     Public Sub Push( ByVal pushValue As E) 26        If top = elements.Length - 1 Then' Stack is full 27             Throw New FullStackException(String.Format( _ 28                "Stack is full, cannot push {0}", pushValue)) 29        End If  30 31        top += 1 ' increment top 32        elements(top) = pushValue' place pushValue on Stack 33     End Sub' Push 34 35     ' return the top element if not empty 36     ' else throw EmptyStackException 37     Public Function Pop() As E 38         If top = -1 Then ' Stack is empty 39           Throw New EmptyStackException("Stack is empty, cannot pop") 40         End If 41 42         top -= 1 ' decrement top 43         Return elements(top + 1)' return top value 44     End Function' Pop 45   End Class' Stack    

Class Stack has two constructors. The parameterless constructor (lines 810)passes the default stack size (10) to the one-argument constructor (line 9) by invoking the constructor in lines 1321. The one-argument constructor (lines 1321) validates the stackSize argument and creates an array of the specified stackSize if it is greater than0 or an array of 10 elements otherwise.

Method Push (lines 2533) first determines whether an attempt is being made to push an element onto a full Stack. If so, lines 2728 throw a FullStackException (declared in Fig. 25.6). If the Stack is not full, line 31 increments the top counter to indicate the new top position, and line 32 places the argument in that location of array elements.

Figure 25.6. FullStackException class declaration

  1  ' Fig. 25.6: FullStackException.vb  2  ' Indicates a stack is full.  3  Public Class FullStackException : Inherits ApplicationException  4     ' parameterless constructor  5     Public Sub New()  6        MyBase.New("Stack is full")  7     End Sub' New  8  9     ' one-parameter constructor 10     Public Sub New( ByVal exception As String) 11        MyBase.New(exception) 12     End Sub ' New 13  End Class ' FullStackException  

Method Pop (lines 3744) first determines whether an attempt is being made to pop an element from an empty Stack. If so, line 39 throws an EmptyStackException (declared in Fig. 25.7). Otherwise, line 42 decrements the top counter to indicate the new top position, and line 43 returns the original top element of the Stack.

Figure 25.7. EmptyStackException class declaration

  1  ' Fig. 25.7: EmptyStackException.vb  2  ' Indicates a stack is empty  3  Public Class EmptyStackException : Inherits ApplicationException  4     ' parameterless constructor  5     Public Sub New()  6        MyBase.New("Stack is empty")  7     End Sub' New  8  9     ' one-parameter constructor 10     Public Sub New( ByVal exception As String) 11        MyBase.New(exception) 12     End Sub' New 13  End Class' EmptyStackException  

Classes FullStackException (Fig. 25.6) and EmptyStackException (Fig. 25.7) each provide a parameterless constructor and a one-argument constructor. The parameterless constructor sets the default error message, and the one-argument constructor sets a custom error message.

As with generic methods, when a generic class is compiled, the compiler performs type checking on the class's type parameters to ensure that they can be used with the code in the generic class. The constraints determine the operations that can be performed on the type parameters. The runtime system replaces the type parameters with the actual types. For class Stack (Fig. 25.5), no type constraint is specified, so the default type constraint, Object, is used. The scope of a generic class's type parameter is the entire class.

Now let's consider an application (Fig. 25.8) that uses the Stack generic class. Lines 89 declare variables of type Stack(Of Double) (pronounced "Stack of Double") and Stack(Of Integer) (pronounced "Stack of Integer"). The types Double and Integer are the type arguments. The compiler replaces the type parameters in the generic class with the type arguments so that the compiler can perform type checking. Method Main instantiates objects doubleStack of size5 (line 12) and integerStack of size 10 (line 13), then calls methods TestPushDouble (lines 2238), TestPopDouble (lines 4158), TestPushInteger (lines 6177) and TestPopInteger (lines 8097) to manipulate the two Stacks in this example.

Figure 25.8. Generic class Stack test program

  1  ' Fig. 25.8: StackTest.vb  2  ' Stack generic class test program.  3  Module StackTest  4     ' create arrays of doubles and integers  5     Dim doubleElements() As Double = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6}  6     Dim integerElements() As Integer = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}  7  8     Dim doubleStack As Stack( Of Double) ' stack stores double objects    9     Dim integerStack As Stack( Of Integer)' stack stores integer objects 10 11     Sub Main() 12         doubleStack = New Stack( Of Double)(5)' Stack of doubles 13         integerStack = New Stack( Of Integer)(10)' Stack of integers 14 15         TestPushDouble()' push doubles onto doubleStack 16         TestPopDouble()' pop doubles from doubleStack 17         TestPushInteger()' push integers onto integerStack 18         TestPopInteger()' pop integers from integerStack 19     End Sub' Main 20 21     ' test Push method with doubleStack 22     Sub TestPushDouble() 23         ' push elements onto stack 24         Try 25            Console.WriteLine(vbCrLf & _ 26               "Pushing elements onto doubleStack") 27 28            ' push elements onto stack 29            For Each element  As Double In doubleElements 30              Console.Write("{0:F1} ", element) 31              doubleStack.Push(element)' push onto doubleStack 32            Next element 33         Catch exception As FullStackException 34            Console.Error.WriteLine() 35            Console.Error.WriteLine("Message: " & exception.Message) 36            Console.Error.WriteLine(exception.StackTrace) 37         End Try 38     End Sub' TestPushDouble 39 40     ' test Pop method with doubleStack 41     Sub TestPopDouble() 42        ' pop elements from stack 43        Try 44           Console.WriteLine(vbCrLf & _ 45              "Popping elements from doubleStack") 46 47           Dim popValue As Double' store element removed from stack 48           ' remove all elements from Stack 49           While True 50              popValue = doubleStack.Pop()' pop from doubleStack 51              Console.Write("{0:F1} ", popValue) 52           End While 53         Catch exception As EmptyStackException 54            Console.Error.WriteLine() 55            Console.Error.WriteLine("Message: " & exception.Message) 56            Console.Error.WriteLine(exception.StackTrace) 57        End Try 58     End Sub' TestPopDouble 59 60     ' test Push method with integerStack 61     Sub TestPushInteger() 62        ' push elements onto stack 63        Try 64           Console.WriteLine(vbCrLf & _ 65              "Pushing elements onto integerStack") 66 67           ' push elements onto stack 68           For Each element As Integer In integerElements 69              Console.Write("{0} ", element) 70              integerStack.Push(element)' push onto integerStack 71           Next element 72        Catch exception As FullStackException 73           Console.Error.WriteLine() 74           Console.Error.WriteLine("Message: " & exception.Message) 75           Console.Error.WriteLine(exception.StackTrace) 76           End Try 77     End Sub' TestPushInteger 78 79     ' test Pop method with integerStack 80     Sub TestPopInteger() 81        ' pop elements from stack 82        Try 83            Console.WriteLine(vbCrLf & _ 84               "Popping elements from integerStack") 85 86            Dim popValue As Integer' store element removed from stack 87            ' remove all elements from Stack 88            While True 89              popValue = integerStack.Pop()' pop from integerStack 90              Console.Write("{0} ", popValue) 91            End While 92        Catch exception As EmptyStackException 93            Console.Error.WriteLine() 94            Console.Error.WriteLine("Message: " & exception.Message) 95            Console.Error.WriteLine(exception.StackTrace) 96        End Try 97      End Sub' TestPopInteger 98  End Module' StackTest 

[View full width]

Pushing elements onto doubleStack 1.1 2.2 3.3 4.4 5.5 6.6 Message: Stack is full, cannot push 6.6 at Stack.Stack`1.Push(E pushValue) in C:\examples\ch25\Fig25_05-08\Stack\Stack.vb :line 27 at Stack.StackTest.TestPushDouble() in C:\examples\ch25\Fig25_05-08\Stack\StackTest .vb:line 31 Popping elements from doubleStack 5.5 4.4 3.3 2.2 1.1 Message: Stack is empty, cannot pop at Stack.Stack`1.Pop() in C:\examples\ch25\Fig25_05-08\Stack\Stack.vb :line 39 at Stack.StackTest.TestPopDouble() in C:\examples\ch25\Fig25_05-08\Stack\StackTest .vb:line 50 Pushing elements onto integerStack 1 2 3 4 5 6 7 8 9 10 11 Message: Stack is full, cannot push 11 at Stack.Stack`1.Push(E pushValue) in C:\examples\ch25\Fig25_05-08\Stack\Stack.vb :line 27 at Stack.StackTest.TestPushInteger() in C:\examples\ch25\Fig25_05-08\Stack\StackTest .vb:line 70 Popping elements from integerStack 10 9 8 7 6 5 4 3 2 1 Message: Stack is empty, cannot pop at Stack.Stack`1.Pop() in C:\examples\ch25\Fig25_05-08\Stack\Stack.vb :line 39 at Stack.StackTest.TestPopInteger() in C:\examples\ch25\Fig25_05-08\Stack\StackTest .vb:line 89



Method TestPushDouble (lines 2238) invokes method Push to place the Double values 1.1,2.2,3.3,4.4 and5.5 stored in array doubleElements onto doubleStack. The loop in lines 2932 terminates when the test program attempts to Push a sixth valueonto doubleStack (which is full, because doubleStack can store only five elements). In this case, the method throws a FullStackException (Fig. 25.6) to indicate that the Stack is full. Lines 3336 catch this exception, and print the message and stack-trace information (see the output of Fig. 25.8). The stack trace indicates the exception that occurred and shows that Stack method Push generated the exception in line 27 of the file Stack.vb (Fig. 25.5). The trace also shows that method Push was called by StackTestmethod TestPushDouble in line 31 of StackTest.vb. This information enables you to determine the methods that were on the method call stack at the time that the exception occurred. The program catches the exception, so the Visual Basic runtime environment considers the exception to have been handled, and the program can continue executing.

Method TestPopDouble (lines 4158) invokes Stack method Pop in an infinite loop to remove all the values from the stack. Note in the output that the values are popped in last-in, first-out (LIFO) orderthis, of course, is the defining characteristic of stacks. The loop in lines 4952 continues until the stack is empty. An EmptyStackException occurs when an attempt is made to pop from the empty stack. This causes the program to proceed to the Catch block (lines 5356) and handle the exception, so that the program can continue executing. When the test program attempts to Pop a sixth value, the doubleStack is empty, so method Pop throws anEmptyStackException.

Method TestPushInteger (lines 6177) invokes Stack method Push to place values onto integerStack until it is full. Method TestPopInteger (lines 8097) invokes Stack method Pop to remove values from integerStack until it is empty. Once again, note that the values pop off in last-in, first-out (LIFO) order.

Creating Generic Methods to Test Class Stack(Of E)

The code is almost identical in methods TestPushDouble and TestPushInteger for pushing values onto a Stack(Of Double) or a Stack(Of Integer), respectively. Similarly the code is almost identical in methods TestPopDouble and TestPopInteger for popping values from a Stack(Of Double) or a Stack(Of Integer), respectively. This presents another opportunity to use generic methods. Figure 25.9 declares generic method TestPush (lines 2542) to perform the same tasks as TestPushDouble and TestPushInteger in Fig. 25.8that is, Push values onto a Stack(Of E). Similarly, generic method TestPop (lines 4462) performs the same tasks as TestPopDouble and TestPopInteger in Fig. 25.8that is, Pop values off a Stack(Of E). Except for the slight differences in the stack traces, the output of Fig. 25.9 matches the output of Fig. 25.8.

Figure 25.9. Passing a generic type Stack to a generic method

  1  ' Fig 25.9: StackTest.vb  2  ' Stack generic class test program.  3  Module StackTest  4     ' create arrays of doubles and integers  5     Dim doubleElements() As Double = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6}  6     Dim integerElements() As Integer = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}  7  8     Dim doubleStack As Stack( Of Double)' stack stores double objects  9     Dim integerStack As Stack( Of Integer)' stack stores integer objects 10 11     Sub Main() 12        doubleStack = New Stack( Of Double)(5)' Stack of doubles 13        integerStack = New Stack( Of Integer)(10)' Stack of integers 14 15        ' push doubles onto doubleStack 16        TestPush("doubleStack", doubleStack, doubleElements) 17        ' pop doubles from doubleStack 18        TestPop("doubleStack", doubleStack) 19        ' push integers onto integerStack 20        TestPush("integerStack", integerStack, integerElements) 21        ' pop integers from integerStack 22        TestPop("integerStack", integerStack) 23     End Sub' Main 24 25     Sub TestPush( Of E)( ByVal name As String, ByVal stack As Stack( Of E), _ 26        ByVal elements() As E)                                                    27        ' push elements onto stack 28        Try 29           Console.WriteLine(vbCrLf & _ 30              "Pushing elements onto " & name) 31 32           ' push elements onto stack 33           For Each element  As E In elements 34              Console.Write("{0} ", element) 35              stack.Push(element)' push onto stack 36           Next element 37        Catch exception As FullStackException 38           Console.Error.WriteLine() 39           Console.Error.WriteLine("Message: " & exception.Message) 40           Console.Error.WriteLine(exception.StackTrace) 41        End Try 42     End Sub' TestPush 43 44     Sub TestPop( Of E)( ByVal name As String, ByVal stack As Stack( Of E)) 45        ' pop elements off stack 46        Try 47           Console.WriteLine(vbCrLf & _ 48              "Popping elements from " & name) 49 50           Dim popValue As E' store element removed from stack 51 52           ' remove all elements from Stack 53           While True 54              popValue = stack.Pop()' pop from stack 55              Console.Write("{0} ", popValue) 56           End While 57        Catch exception As EmptyStackException 58           Console.Error.WriteLine() 59           Console.Error.WriteLine("Message: " & exception.Message) 60           Console.Error.WriteLine(exception.StackTrace) 61        End Try 62     End Sub' TestPop 63  End Module' StackTest  

[View full width]

Pushing elements onto doubleStack 1.1 2.2 3.3 4.4 5.5 6.6 Message: Stack is full, cannot push 6.6 at Stack.Stack`1.Push(E pushValue) in C:\examples\ch25\Fig25_09\Stack\Stack.vb:line 27 at Stack.StackTest.TestPush[E](String name, Stack`1 stack, IEnumerable`1 elements) in C:\examples\ch25\Fig25_09\Stack\StackTest .vb:line 35 Popping elements from doubleStack 5.5 4.4 3.3 2.2 1.1 Message: Stack is empty, cannot pop at Stack.Stack`1.Pop() in C:\examples\ch25\Fig25_09\Stack\Stack.vb :line 39 at Stack.StackTest.TestPop[E](String name, Stack`1 stack) in C:\examples\ch25\Fig25_09\Stack\StackTest .vb:line 54 Pushing elements onto integerStack 1 2 3 4 5 6 7 8 9 10 11 Message: Stack is full, cannot push 11 at Stack.Stack`1.Push(E pushValue) in C:\examples\ch25\Fig25_09\Stack\Stack.vb :line 27 at Stack.StackTest.TestPush[E](String name, Stack`1 stack, IEnumerable`1 elements) in C:\examples\ch25\Fig25_09\Stack\StackTest .vb:line 35 Popping elements from integerStack 10 9 8 7 6 5 4 3 2 1 Message: Stack is empty, cannot pop at Stack.Stack`1.Pop() in C:\examples\ch25\Fig25_09\Stack\Stack.vb :line 39 at Stack.StackTest.TestPop[E](String name, Stack`1 stack) in C:\examples\ch25\Fig25_09\Stack\StackTest .vb:line 54



Method Main (lines 1123) creates the Stack(Of Double) and Stack(Of Integer) objects (lines 1213) . Lines 1622 invoke generic methods TestPush and TestPop to test the Stack objects.

Generic method TestPush (lines 2542) uses type parameter E (specified in line 25) to represent the type stored in the Stack. The generic method takes three argumentsa String that represents the name of the Stack object for output purposes, an object of type Stack(Of E) and an array of type E that contains the elements that will be Push edonto Stack(Of E). Note that the compiler enforces consistency between the type of the Stack and the elements that will be pushed onto the Stack when Push is invoked, which is the type argument of the generic method call. Generic method TestPop (lines 4462) takes two argumentsa String that represents the name of the Stack object for output purposes and an object of type Stack(Of E).




Visual BasicR 2005 for Programmers. DeitelR Developer Series
Visual Basic 2005 for Programmers (2nd Edition)
ISBN: 013225140X
EAN: 2147483647
Year: 2004
Pages: 435

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