![]() ![]() |
![]() |
|||||||
![]() ![]() |
||||||||
![]()
![]() ![]() ![]() ![]() ![]() ![]() ![]() |
![]()
Class actAndy Redfern Using classes to build an object-oriented application in Visual Basic 5.0
A class is some data and the code associated with accessing that data. This close relationship between the data and the code is called encapsulation. For example, you might have a class called Employee and a piece of data in that class called StaffId. The data is stored in a variable within the class and you could access it directly in much the same way as you would an element within a user-defined type. However, using a class implementation has a number of powerful advantages. First, you can add range checking to the assignment of a value to a variable. For example, if a valid StaffId must be bigger than 1,000, then you can check for that in your assignment code and return an error if an invalid value is used. Second, if the implementation of the class changes, you can simply recompile with the new class code in place to see the changes made. For example, you might store StaffId as an Integer, then find that it now needs to be stored as a Long. Changing the code in the class is straightforward, and all the code that's dependent on that class will still work. This close marriage between data and code means that you can create your own object types. The other two features of using a class approach are polymorphism and inheritance. Polymorphism is the ability to create interfaces to objects that are identical from the developer's point of view when using the class, but are different within the class itself. For example, if you had two classes called Folder and Document, both would require the same methods--Create New, Delete, Move, Copy and so on--but the actions of Document.Copy and of Folder. Copy would be different. To achieve this you'd use the nearest thing to inheritance offered by Visual Basic. This allows you to create a base class that your other classes use. In this example, you'd create an abstract class called DiskObj, then implement two new objects with identical interfaces called Document and Folder. Then, when your application is running, you don't need to know whether an object is a Document or a Folder, as Visual Basic will work this out and call the necessary function. Let's create some classes and see how they work. The first useful tool you should acquaint yourself with is the Visual Basic Class Builder utility. This allows classes to be specified as a structure, then writes the code into the CLS files for you. First we're going to create a very simple class to see how the property interface works. Open a new Standard EXE project and select the Class Builder utility from the Add-Ins menu. If it's not there, then you'll need to add it using the Add-In Manager. When you're in the Class Builder utility, click the Add New Class item, then type in 'Person' as the name of your class. Click on the Attributes tab and type a text description of the class into the box. This will help you if you ever use the object browser (Figure 1), as this description will appear alongside the selected object. For this example, just type in 'my first class'. After pressing OK you should see a new class called Person attached to the Project 1. From the toolbar, select 'Add new property to current class'. Call it 'Name' and leave the rest of the items as marked. Again on the Attributes tab you can add a description. Select Update Project from the File menu. At this stage the Class Builder is automatically generating the class for you. Close down the Class Builder and you should see the code shown in Listing 1. Let's look at it more closely to see what the key elements of the class are.
The first item is the variable used to store the Person's name. The keyword Private means that the value of mvarName can only be changed within this class module itself--it can't be referenced directly from elsewhere in the project. This means you have full control over access to the value in mvarName, through the three property procedures defined here--Let, Set and Get. Let allows a value to be assigned to the variable. In this implementation it uses the Public keyword, allowing this method to be called from anywhere within Project 1 where there's a valid Person class object. To use the Let function in your code, simply type in the code: Dim newperson as person Set newperson = New person Person.name = "Bill Hubbard" Whenever the assignment is made, the Let code is run, so you should add a data-validation routine here, such as adding age as another property of a person. The Let statement would be the place to do this. The Set function isn't actually required in this example, but appears because we didn't define the type of Name. Because we left it as a variant data type, Visual Basic has added the Set code so that Name can be assigned to an object value. You could either delete this section if you didn't need it, or if you specify the property type as String when you create the class, the Set function isn't automatically generated. The final property control method is the Get function. Again, you're not accessing the variable directly; the value is passed by the Get function. The code: NewName = newperson.name will pass the value of whatever is stored in the Name property of the newperson class. You can create a property for a class just by adding a public variable to it. Adding: Public name as string to your class will create a public variable that you access by referencing it through the class name. So, if you create an instance of the object called newperson, then: newperson.name="Bill Hubbard" will set the value as before. However, the data hiding provided by the Let/Get combination is useful, as it lets you monitor how a variable is used, and add range or value checking if required, making your application more robust. It's also worth noting that you won't save a function call by not implementing a Let/Get interface, as VB will add the equivalent of a Let/Get if you don't. If at any stage you make a mistake, you might be tempted to try using Class Builder again. This will work, but it has some limitations. If you manually modify the class, these changes won't be reflected in the visual view. Also, if you add a class by writing the code yourself, Class Builder won't recognise it. This can be confusing and can lead to errors. I suggest that until the Class Builder is improved so it can read your code and create a visual view from it, you regard it as a write-only utility. However, at this stage we can still use Class Builder. Select it again and add the properties Age as an integer and DateOfBirth as a date. Then update the project. You should now have three variables and, if you defined Name as string, three pairs Let/Get statements. However, we don't want people to be able to set the value of Age, as we want to calculate it from the DateOfBirth, so comment out the line: mvarAge=vData and add a message box to show an error if someone mistakenly tries to set the value of Age. Next we need to add some code to the Let DateOfBirth function to calculate the person's age. A simple if not very robust technique is to subtract today's date from the DateOfBirth, then access the number of years using the Year function. You'd then need to subtract 1900 from that figure to get the number of years. The following line of code should do the trick: mvarAge = Year(Now - vData) 3 - 1900 We've now created an object with three properties, one of which is read only. The final element of the VB class interface is to implement the special methods that are called when a class is created or deleted. In object-oriented programming these are the constructor and the destructor methods. In VB they're called Initialize and Terminate. You add the Initialize method to your class by selecting Class from the list box in the top left-hand corner of the editing window. This will automatically add: Private Sub Class_Initialize() End Sub to your application. If you select Terminate in the other list box at the top of the editing window, then you'll get: Private Sub Class_Terminate End Sub as well. These methods can't be called directly as they're private, but whenever you create a new instance of an object, or delete an object, then one of these methods is called. In this case let's use the Initialize routine to set default values for all the elements of the class by adding the code: mvarAge = 0 mvarDateOfBirth = 0 mvarName = "" and as a test add the line: MsgBox "A person has been 3 created" as well. This will enable us to see when the Initialize routine runs. We can reference the class variables directly in the Initialize method because the code we're writing is in the Person class module, so the private keyword has no effect. You can also add: MsgBox "A person has been 3 destroyed" to the Terminate routine. Your class should now look like Listing 2. Let's create a short program to test the object and see what happens when the various methods are called. Listing 3 creates a new person, assigns some code, then destroys the person when they go out of scope after the routine finishes. Add this code to form1 of the project with the Person class you've created, then run it using F8 so you can step through the code line by line. What should happen is that the Dim statement will have no effect except in reserving space for the Person object. When you execute the Set line, Class_Initialize will run and the message box saying the person has been created should appear once the variables have been set. Attempting to set a value to the Age routine will result in the message box error appearing. Generally, it's not good practice to put message boxes in class code--it's much better to create an error event. We'll look at events more closely next month. The rest of the code should run as usual, with the age appearing in the debug window after executing the Debug.Print line. When the End Sub executes, our Person object will go out of scope, so will be destroyed. At this point, the Terminate routine will be called. Although we don't execute any code here, you could use this routine to check that an object has been saved before the data is lost. And that's your first object-oriented application in Visual Basic 5.0. Because this column has to cover a lot of new concepts, the functionality shown is limited. Next month we'll look more at polymorphism and user-defined events, and develop a useful object-oriented application.One of the most powerful new features of Visual Basic 5.0 is the inclusion of support for classes, and a program interface for creating your own classes and manipulating them. This month we'll look at classes, how they work and the benefits they bring to VB programmers. A class is some data and the code associated with accessing that data. This close relationship between the data and the code is called encapsulation. For example, you might have a class called Employee and a piece of data in that class called StaffId. The data is stored in a variable within the class and you could access it directly in much the same way as you would an element within a user-defined type. However, using a class implementation has a number of powerful advantages. First, you can add range checking to the assignment of a value to a variable. For example, if a valid StaffId must be bigger than 1,000, then you can check for that in your assignment code and return an error if an invalid value is used. Second, if the implementation of the class changes, you can simply recompile with the new class code in place to see the changes made. For example, you might store StaffId as an Integer, then find that it now needs to be stored as a Long. Changing the code in the class is straightforward, and all the code that's dependent on that class will still work. This close marriage between data and code means that you can create your own object types. The other two features of using a class approach are polymorphism and inheritance. Polymorphism is the ability to create interfaces to objects that are identical from the developer's point of view when using the class, but are different within the class itself. For example, if you had two classes called Folder and Document, both would require the same methods--Create New, Delete, Move, Copy and so on--but the actions of Document.Copy and of Folder. Copy would be different. To achieve this you'd use the nearest thing to inheritance offered by Visual Basic. This allows you to create a base class that your other classes use. In this example, you'd create an abstract class called DiskObj, then implement two new objects with identical interfaces called Document and Folder. Then, when your application is running, you don't need to know whether an object is a Document or a Folder, as Visual Basic will work this out and call the necessary function. Let's create some classes and see how they work. The first useful tool you should acquaint yourself with is the Visual Basic Class Builder utility. This allows classes to be specified as a structure, then writes the code into the CLS files for you. First we're going to create a very simple class to see how the property interface works. Open a new Standard EXE project and select the Class Builder utility from the Add-Ins menu. If it's not there, then you'll need to add it using the Add-In Manager. When you're in the Class Builder utility, click the Add New Class item, then type in 'Person' as the name of your class. Click on the Attributes tab and type a text description of the class into the box. This will help you if you ever use the object browser (Figure 1 on page 259), as this description will appear alongside the selected object. For this example, just type in 'my first class'. After pressing OK you should see a new class called Person attached to the Project 1. From the toolbar, select 'Add new property to current class'. Call it 'Name' and leave the rest of the items as marked. Again on the Attributes tab you can add a description. Select Update Project from the File menu. At this stage the Class Builder is automatically generating the class for you. Close down the Class Builder and you should see the code shown in Listing 1. Let's look at it more closely to see what the key elements of the class are. The first item is the variable used to store the Person's name. The keyword Private means that the value of mvarName can only be changed within this class module itself--it can't be referenced directly from elsewhere in the project. This means you have full control over access to the value in mvarName, through the three property procedures defined here--Let, Set and Get. Let allows a value to be assigned to the variable. In this implementation it uses the Public keyword, allowing this method to be called from anywhere within Project 1 where there's a valid Person class object. To use the Let function in your code, simply type in the code: Dim newperson as person Set newperson = New person Person.name = "Bill Hubbard" Whenever the assignment is made, the Let code is run, so you should add a data-validation routine here, such as adding age as another property of a person. The Let statement would be the place to do this. The Set function isn't actually required in this example, but appears because we didn't define the type of Name. Because we left it as a variant data type, Visual Basic has added the Set code so that Name can be assigned to an object value. You could either delete this section if you didn't need it, or if you specify the property type as String when you create the class, the Set function isn't automatically generated. The final property control method is the Get function. Again, you're not accessing the variable directly; the value is passed by the Get function. The code: NewName = newperson.name will pass the value of whatever is stored in the Name property of the newperson class. You can create a property for a class just by adding a public variable to it. Adding: Public name as string to your class will create a public variable that you access by referencing it through the class name. So, if you create an instance of the object called newperson, then: newperson.name="Bill Hubbard" will set the value as before. However, the data hiding provided by the Let/Get combination is useful, as it lets you monitor how a variable is used, and add range or value checking if required, making your application more robust. It's also worth noting that you won't save a function call by not implementing a Let/Get interface, as VB will add the equivalent of a Let/Get if you don't. If at any stage you make a mistake, you might be tempted to try using Class Builder again. This will work, but it has some limitations. If you manually modify the class, these changes won't be reflected in the visual view. Also, if you add a class by writing the code yourself, Class Builder won't recognise it. This can be confusing and can lead to errors. I suggest that until the Class Builder is improved so it can read your code and create a visual view from it, you regard it as a write-only utility. However, at this stage we can still use Class Builder. Select it again and add the properties Age as an integer and DateOfBirth as a date. Then update the project. You should now have three variables and, if you defined Name as string, three pairs Let/Get statements. However, we don't want people to be able to set the value of Age, as we want to calculate it from the DateOfBirth, so comment out the line: mvarAge=vData and add a message box to show an error if someone mistakenly tries to set the value of Age. Next we need to add some code to the Let DateOfBirth function to calculate the person's age. A simple if not very robust technique is to subtract today's date from the DateOfBirth, then access the number of years using the Year function. You'd then need to subtract 1900 from that figure to get the number of years. The following line of code should do the trick: mvarAge = Year(Now - vData) 3 - 1900 We've now created an object with three properties, one of which is read only. The final element of the VB class interface is to implement the special methods that are called when a class is created or deleted. In object-oriented programming these are the constructor and the destructor methods. In VB they're called Initialize and Terminate. You add the Initialize method to your class by selecting Class from the list box in the top left-hand corner of the editing window. This will automatically add: Private Sub Class_Initialize() End Sub to your application. If you select Terminate in the other list box at the top of the editing window, then you'll get: Private Sub Class_Terminate End Sub as well. These methods can't be called directly as they're private, but whenever you create a new instance of an object, or delete an object, then one of these methods is called. In this case let's use the Initialize routine to set default values for all the elements of the class by adding the code: mvarAge = 0 mvarDateOfBirth = 0 mvarName = "" and as a test add the line: MsgBox "A person has been 3 created" as well. This will enable us to see when the Initialize routine runs. We can reference the class variables directly in the Initialize method because the code we're writing is in the Person class module, so the private keyword has no effect. You can also add: MsgBox "A person has been 3 destroyed" to the Terminate routine. Your class should now look like Listing 2. Let's create a short program to test the object and see what happens when the various methods are called. Listing 3 creates a new person, assigns some code, then destroys the person when they go out of scope after the routine finishes. Add this code to form1 of the project with the Person class you've created, then run it using F8 so you can step through the code line by line. What should happen is that the Dim statement will have no effect except in reserving space for the Person object. When you execute the Set line, Class_Initialize will run and the message box saying the person has been created should appear once the variables have been set. Attempting to set a value to the Age routine will result in the message box error appearing. Generally, it's not good practice to put message boxes in class code--it's much better to create an error event. We'll look at events more closely next month. The rest of the code should run as usual, with the age appearing in the debug window after executing the Debug.Print line. When the End Sub executes, our Person object will go out of scope, so will be destroyed. At this point, the Terminate routine will be called. Although we don't execute any code here, you could use this routine to check that an object has been saved before the data is lost. And that's your first object-oriented application in Visual Basic 5.0. Because this column has to cover a lot of new concepts, the functionality shown is limited. Next month we'll look more at polymorphism and user-defined events, and develop a useful object-oriented application. |
![]()
| ||||||
Copyright © 1997 ZDNet UK. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of ZDNet is prohibited. ZDNet and the ZDNet logo are trademarks of Ziff-Davis Publishing Company. |