We described abstract classes as those intended for inheritance. Another type of class designed for this purpose is referred to as an interface. An interface is a class that creates a foundation that new derived classes can use. As done for an abstract class, you can create original behavior that the deriving classes would use. Unlike abstract classes, you don't implement the members (properties and procedures) of the interface. The general idea of an interface is only to lay a foundation, as creating a structural base, that the new classes would follow, although they can customize the behavior(s) of the parent interface but the parent interface does not "decide" what the behavior of a member would be. To create an interface, you start with the Interface keyword followed by the name of the interface. You end the interface definition with an End Interface line. By tradition or good habit, the name of an interface starts with I. Here is an example of a starting interface: File: RegularTriangle.vbPublic Interface ITriangle End Interface After creating an interface, you can derive a class from it. When deriving from an interface, instead of the Inherits keyword, you use Implements followed by the name of the interface. Here is an example of a new class named Regular and that is based on the above ITriangle interface: File: RegularTriangle.vbPublic Interface ITriangle End Interface Public Class RegularTriangle Implements ITriangle End Class As with other classes, once you have derived the class, you can create objects from it and instantiate it using the New operator. Here is an example: File: Exercise.vbModule Exercise Public Function Main() As Integer Dim reg As RegularTriangle reg = New RegularTriangle Return 0 End Function End Module As mentioned earlier, the purpose of having an interface is to create a skeleton that derived classes would follow. To do this, in the body of the interface, you can create the necessary members that you want to make available to new classes. The members can be the same types of methods or properties as those we have used in classes so far. Here are examples: File: RegularTriangle.vbPublic Interface ITriangle ReadOnly Property Name() As String Property Base() As Double Property Height() As Double Function CalculatePerimeter() As Double Function CalculateArea() As Double End Interface The primary rule you must observe when deriving a class from an interface is that you must implement each member of the interface in the derived class. If you omit implementing a member of the parent interface, you would receive an error. When implementing a member of the interface, it must be followed by the Implements keyword, the name of the interface, the period operator, and the name of the member that it is implementing. Based on this, our Regular class can implement the ITriangle interface as follows: File: RegularTriangle.vbPublic Interface ITriangle ReadOnly Property Name() As String Property Base() As Double Property Height() As Double Function CalculatePerimeter() As Double Function CalculateArea() As Double End Interface Public Class RegularTriangle Implements ITriangle Public bas As Double Public hgt As Double Public sd1 As Double Public sd2 As Double ' Default constructor: the user will specify the dimensions Public Sub New() bas = 0 hgt = 0 sd1 = 0 sd2 = 0 End Sub ' A triangle based on known base and height Public Sub New(ByVal b As Double, ByVal h As Double) bas = b hgt = h End Sub ' A triangle based on the measurements of the sides Public Sub New(ByVal b As Double, ByVal side1 As Double, ByVal side2 As Double) bas = b sd1 = side1 sd2 = side2 End Sub ' A triangle whose all sides and the height are known Public Sub New(ByVal b As Double, ByVal h As Double, _ ByVal side1 As Double, ByVal side2 As Double) bas = b hgt = h sd1 = side1 sd2 = side2 End Sub Public Property Base() As Double Implements ITriangle.Base Get Return bas End Get Set(ByVal Value As Double) If bas < 0 Then bas = 0 Else bas = Value End If End Set End Property Public Function CalculateArea() As Double Implements ITriangle.CalculateArea Return bas * hgt / 2 End Function Public Function CalculatePerimeter() As Double Implements _ ITriangle.CalculatePerimeter Return bas + sd1 + sd2 End Function Public Property Height() As Double Implements ITriangle.Height Get Return hgt End Get Set(ByVal Value As Double) If hgt < 0 Then hgt = 0 Else hgt = Value End If End Set End Property Public ReadOnly Property Name() As String Implements ITriangle.Name Get Return "Regular Triangle" End Get End Property End Class Once the class has been defined like this, you can then instantiate and use it. Here is an example: File: Exercise.vbModule Exercise Public Function Main() As Integer Dim reg As RegularTriangle = New RegularTriangle(35.28, 26.44) Console.WriteLine("Triangle Type: {0}", reg.Name) Console.WriteLine("=-= Characteristics =-=") Console.WriteLine("Base: {0}", reg.Base) Console.WriteLine("Height: {0}", reg.Height) Console.WriteLine("Area: {0}", reg.CalculateArea) Return 0 End Function End Module This would produce: Triangle Type: Regular Triangle =-= Characteristics =-= Base: 35.28 Height: 26.44 Area: 466.4016 In the same way, you can derive other classes from an interface. For example, from our ITriangle class, you can derive an isosceles, a right, or an equilateral triangle. Always remember that when you derive a class, you must implement all of the members of the interface. You can also add new members as you see fit.
Like a regular class, an interface can be derived from another interface but an interface cannot derive from a class. To create an interface based on another, use the Inherits keyword as we have used in other classes. Here is an example: File: RegularTriangle.vbPublic Interface IGeometricShape End Interface Public Interface ITriangle Inherits IGeometricShape End Interface As mentioned for the interfaces, you can use the parent interface to list the members that the deriving classes would implement. Still remember that since an interface cannot implement a member, the member of the parent interface cannot be defined in a derived interface. This implement would wait for the actual class(es) that would be based on the child (or even the parent) interface. Here is an example: File: RegularTriangle.vbPublic Interface IGeometricShape ReadOnly Property Type() As String End Interface Public Interface ITriangle Inherits IGeometricShape ReadOnly Property Name() As String Property Base() As Double Property Height() As Double Function CalculatePerimeter() As Double Function CalculateArea() As Double End Interface After deriving a class from an interface, when defining the class, you must implement the member of the immediate interface and those of the ancestor interface(s). Here is an example: File: RegularTriangle.vbPublic Interface IGeometricShape ReadOnly Property Type() As String End Interface Public Interface ITriangle Inherits IGeometricShape ReadOnly Property Name() As String Property Base() As Double Property Height() As Double Function CalculatePerimeter() As Double Function CalculateArea() As Double End Interface Public Class RegularTriangle Implements ITriangle Public bas As Double Public hgt As Double Public sd1 As Double Public sd2 As Double Public ReadOnly Property Type() As String Implements ITriangle.type Get Return "Triangle" End Get End Property ' Default constructor: the user will specify the dimensions Public Sub New() bas = 0 hgt = 0 sd1 = 0 sd2 = 0 End Sub ' A triangle based on known base and height Public Sub New(ByVal b As Double, ByVal h As Double) bas = b hgt = h End Sub ' A triangle based on the measurements of the sides Public Sub New(ByVal b As Double, ByVal side1 As Double, ByVal side2 As Double) bas = b sd1 = side1 sd2 = side2 End Sub ' A triangle whose all sides and the height are known Public Sub New(ByVal b As Double, ByVal h As Double, _ ByVal side1 As Double, ByVal side2 As Double) bas = b hgt = h sd1 = side1 sd2 = side2 End Sub Public Property Base() As Double Implements ITriangle.Base Get Return bas End Get Set(ByVal Value As Double) If bas < 0 Then bas = 0 Else bas = Value End If End Set End Property Public Function CalculateArea() As Double Implements ITriangle.CalculateArea Return bas * hgt / 2 End Function Public Function CalculatePerimeter() As Double Implements _ ITriangle.CalculatePerimeter Return bas + sd1 + sd2 End Function Public Property Height() As Double Implements ITriangle.Height Get Return hgt End Get Set(ByVal Value As Double) If hgt < 0 Then hgt = 0 Else hgt = Value End If End Set End Property Public ReadOnly Property Name() As String Implements ITriangle.Name Get Return "Regular" End Get End Property End Class Here is an example of testing the class: File: Exercise.vbModule Exercise Public Function Main() As Integer Dim reg As RegularTriangle = New RegularTriangle(35.28, 26.44) Console.WriteLine("Shape Type: {0}", reg.Type) Console.WriteLine("Triangle Type: {0}", reg.Name) Console.WriteLine("=-= Characteristics =-=") Console.WriteLine("Base: {0}", reg.Base) Console.WriteLine("Height: {0}", reg.Height) Console.WriteLine("Area: {0}", reg.CalculateArea) Return 0 End Function End Module This would produce: Shape Type: Triangle Triangle Type: Regular =-= Characteristics =-= Base: 35.28 Height: 26.44 Area: 466.4016
Multiple inheritance consists of creating a class that is based on more than one parent. In the Microsoft Visual Basic language (in fact in the .NET Framework), you cannot derive a class from more than one class. This functionality is available only with interfaces. To create a class based on more than one interface, after the Implements keyword, enter the name of each interface and separate them with commas. Here is an example: Public Interface IGeometricShape ReadOnly Property Type() As String End Interface Public Interface ICalculation End Interface Public Interface ITriangle Inherits IGeometricShape, ICalculation End Interface The same rules apply for multiple inheritance: you must implements all members of each parent interface. Besides deriving from an interface, you can also create a class that is based on a class and one or more interfaces. To do this, under the line that specifies the name of the class, use the Inherits keyword to specify the name of the parent, press Enter, and use the Implements keyword to specify the name of the class that serves as the parent interface. Here is an example: Public Interface IGeometricShape ReadOnly Property Type() As String End Interface Public Interface ICalculation End Interface Public Class Geometry End Class Public Interface ITriangle Inherits IGeometricShape, ICalculation End Interface Public Class RegularTriangle Inherits Geometry Implements ITriangle End Class In the same way, you can create a class that is based on more than one interface but it can be based on only one class.
In Lesson 5, we saw that a procedure was an assignment that complemented a program. We also saw that there were two types of procedures: functions and sub routines. These concepts of sub procedures and functions also apply to classes. This means that a procedure that process a class, it can be passed a class as argument, and it can return a class. As described in Lesson 8, to create a sub procedure, type the Sub keyword followed by a name, followed by parentheses and an end of line. To indicate the end of a sub procedure, you must type End Sub. Therefore, the syntax of a sub procedure is: Sub ProcedureName() End Sub Between the Sub and the End Sub lines, you can declare the necessary variables and they can be of regular types or based on classes. Here is an example: Module Exercise Private Sub ShowCharacteristics() Dim reg As RegularTriangle = New RegularTriangle(35.28, 26.44) End Sub Public Function Main() As Integer Return 0 End Function End Module After declaring a variable based on a class, you can regularly use it as we have done with objects in the Main() function so far. Here is an example: File: Exercise.vbModule Exercise Private Sub ShowCharacteristics() Dim reg As RegularTriangle = New RegularTriangle(35.28, 26.44) Console.WriteLine("Shape Type: {0}", reg.Type) Console.WriteLine("Triangle Type: {0}", reg.Name) Console.WriteLine("=-= Characteristics =-=") Console.WriteLine("Base: {0}", reg.Base) Console.WriteLine("Height: {0}", reg.Height) Console.WriteLine("Area: {0}", reg.CalculateArea) End Sub Public Function Main() As Integer ShowCharacteristics() Return 0 End Function End Module In the same way, you can declare as many class variables as you see fit in a procedure.
So far, as we have learned since Lesson, we know that a function can be used to return a value. In the same way, you can create a function that returns an object of a class. When creating such a function, set its type as that of the class it would return. The formula to follow is still: Function FunctionName() As ClassName End Function In the body of the class, which is the section between the Function and the End Function lines, you can perform any assignment you judge necessary. For example you can declare local variables. Before exiting the function, you must make sure it returns a value based on its As type. You can do this using the Return keyword followed by the value to return. Here is an example: Private Function CreateTriangle() As RegularTriangle Dim regTri As RegularTriangle Dim base As Double, height As Double Console.WriteLine("Enter the measurements of the triangle") Console.Write("Base: ") base = CDbl(Console.ReadLine()) Console.Write("Height: ") height = CDbl(Console.ReadLine()) regTri = New RegularTriangle(base, height) Return regTri End Function After defining the function, since it returns a value, when calling it, you can assign it to a variable of the type that it returns. Here is an example: Module Exercise Private Function CreateTriangle() As RegularTriangle Dim regTri As RegularTriangle Dim base As Double, height As Double Console.WriteLine("Enter the measurements of the triangle") Console.Write("Base: ") base = CDbl(Console.ReadLine()) Console.Write("Height: ") height = CDbl(Console.ReadLine()) regTri = New RegularTriangle(base, height) Return regTri End Function Private Sub ShowCharacteristics() Dim reg As RegularTriangle = New RegularTriangle reg = CreateTriangle() Console.WriteLine("Shape Type: {0}", reg.Type) Console.WriteLine("Triangle Type: {0}", reg.Name) Console.WriteLine("=-= Characteristics =-=") Console.WriteLine("Base: {0}", reg.Base) Console.WriteLine("Height: {0}", reg.Height) Console.WriteLine("Area: {0}", reg.CalculateArea) End Sub Public Function Main() As Integer ShowCharacteristics Return 0 End Function End Module Here is a test of the above code: Enter the measurements of the triangle Base: 18.44 Height: 12.62 Shape Type: Triangle Triangle Type: Regular =-= Characteristics =-= Base: 18.44 Height: 12.62 Area: 116.3564
Like a regular variable, a class can be passed as argument to a procedure. When a procedure receives such an argument, it can process it as necessary. All the rules we reviewed for regular variables apply to a class, as long as you keep in mind that an object has members that you may need to be aware of. When calling the procedure, make sure you pass it a value argument based on the class it passed to it. Here is an example of a class passed as argument: Module Exercise Private Function CreateTriangle() As RegularTriangle Dim regTri As RegularTriangle Dim base As Double, height As Double Console.WriteLine("Enter the measurements of the triangle") Console.Write("Base: ") base = CDbl(Console.ReadLine()) Console.Write("Height: ") height = CDbl(Console.ReadLine()) regTri = New RegularTriangle(base, height) Return regTri End Function Private Sub ShowCharacteristics(ByVal reg As RegularTriangle) Console.WriteLine("Shape Type: {0}", reg.Type) Console.WriteLine("Triangle Type: {0}", reg.Name) Console.WriteLine("=-= Characteristics =-=") Console.WriteLine("Base: {0}", reg.Base) Console.WriteLine("Height: {0}", reg.Height) Console.WriteLine("Area: {0}", reg.CalculateArea) End Sub Public Function Main() As Integer Dim Angle3 = CreateTriangle() Console.WriteLine() ShowCharacteristics(Angle3) Console.WriteLine() Return 0 End Function End Module Besides the function, in Lesson 5, we saw that, by passing an argument by reference, a sub procedure could return a value. This characteristic also applies to a class passed as argument. When passing the argument, precede it with the ByRef keyword. In the procedure, process the argument as you see fit, unless you choose not to. When calling the procedure, pass it a valid variable based on the type of the argument. Here is an example: Module Exercise Private Sub CreateTriangle(ByRef regTri As RegularTriangle) Dim base As Double, height As Double Console.WriteLine("Enter the measurements of the triangle") Console.Write("Base: ") base = CDbl(Console.ReadLine()) Console.Write("Height: ") height = CDbl(Console.ReadLine()) regTri = New RegularTriangle(base, height) End Sub Private Sub ShowCharacteristics(ByVal reg As RegularTriangle) Console.WriteLine("Shape Type: {0}", reg.Type) Console.WriteLine("Triangle Type: {0}", reg.Name) Console.WriteLine("=-= Characteristics =-=") Console.WriteLine("Base: {0}", reg.Base) Console.WriteLine("Height: {0}", reg.Height) Console.WriteLine("Area: {0}", reg.CalculateArea) End Sub Public Function Main() As Integer Dim Angle3 As RegularTriangle = New RegularTriangle CreateTriangle(Angle3) Console.WriteLine() ShowCharacteristics(Angle3) Console.WriteLine() Return 0 End Function End Module Here is an example of testing it: Enter the measurements of the triangle Base: 50.05 Height: 25.52 Shape Type: Triangle Triangle Type: Regular =-= Characteristics =-= Base: 50.05 Height: 25.52 Area: 638.638
Like a regular variable, a class can be locally declared as static, using the Static keyword. If the value of such a locally declared variable changes, when the procedure ends, the value of the variable is changed and would be kept until the next call.
When passing an argument of a class, you can specify that it is not required. Such an argument is considered optional. To specify that an argument is optional, when creating its procedure, type the Optional keyword to the left of the argument's name and assign it the default value. All the other rules we reviewed for optional arguments are also applied here.
If you want to create various procedures that takes a class argument, you can create a procedure with the same name but different signatures. This is referred to as overloading the procedure. When doing this, follow the same rules we reviewed for overloading a procedure: the must have the same name, they cannot have the same number of argument when the arguments at each position are of the same types. |
|
|||||||||||||||||||||||||||
|