STRUCTURES

Structures are very similar to classes. The syntax for declaring a structure is as follows:

[attribute_list] [Partial] [accessibility] [Shadows] _
Structure name[(Of type_list)]
    [Implements interface]
    statements
End Structure

The only thing that all structure declarations must include is the Structure clause (including the structure’s name) and the End Structure statement. The rest is optional.

Unlike a class, however, a structure cannot be empty. It must contain at least one variable or event declaration. The following code defines a valid structure. Its only member is a Private variable, so this structure wouldn’t be of much use, but it is valid.

Structure EmptyStructure
    Private Num As Integer
End Structure

The structure’s attribute_list and accessibility clauses, Shadows and Partial keywords, and the Implements statement are the same as those for classes. See the earlier sections discussing these keywords for details.

There are two main differences between a structure and a class: Structures cannot inherit, and structures are value types rather than reference types.

Structures Cannot Inherit

Unlike a class, a structure cannot inherit so it cannot use the MustInherit, NotInheritable, or Inherits keywords; however, like a class, a structure can implement any number of interfaces. You can use interface inheritance to define inheritance-mimicking hierarchies of structures, and you can simulate multiple inheritance by making a structure implement multiple interfaces.

Structures Are Value Types

The biggest difference between a structure and a class is in how each allocates memory for its data. Classes are reference types. That means an instance of a class is actually a reference to the object’s storage in memory. When you create an instance of a class, Visual Basic creates a reference that points to the object’s actual location in memory.

In contrast, structures are value types. An instance of a structure contains the data inside the structure rather than simply points to it. Figure 23-1 illustrates the difference.

FIGURE 23-1: A structure contains the data, whereas a class object contains a reference that points to data.

image

The difference between reference and value type has several important consequences that are described in the following sections.

Memory Required

The difference in memory required by classes and structures is small when you consider only a single object. If you look at an array, however, the distinction is more important. An array of class objects contains references to data in some other part of memory. When you first declare the array, the references all have the value Nothing, so they don’t point to any data and no memory is allocated for the data. The references take 4 bytes each, so the array uses only 4 bytes per array entry.


ONE SIZE DOESN’T FIT ALL
Actually, the size of a reference is not necessarily 4 bytes. On a 64-bit system, references are larger. In general, you should not assume a reference has a particular size. Just be aware that references take relatively little memory.

An array of structure instances, on the other hand, allocates space for the data inside the array. If each structure object takes up 1000 bytes of memory, then an array containing N items uses 1000 * N bytes of memory. Each structure instance’s memory is allocated, whether or not its fields contain meaningful data.

Figure 23-2 illustrates this situation. The array of class objects on the left uses very little memory when the references are Nothing. The array of structure objects on the right uses a lot of memory even if its elements have not been initialized.

FIGURE 23-2: An array of class objects contains small references to data, many of which may be Nothing. An array of structures takes up a significant amount of memory.

image

If you must use a large array of objects where only a few at a time will have values other than Nothing, using a class may save the program a considerable amount of memory. If you will need most of the objects to have values other than Nothing at the same time, it may be faster to allocate all the memory at once using a structure. This will also use slightly less memory, because an array of class references requires 4 extra bytes per entry to hold the references.


PERFORMANCE ANXIETY
In theory, you may see a slight performance benefit to using an array of structures if you want them initialized to default values. The array will be allocated and later freed in a single step, and its memory will be contiguous, so for some applications, this kind of array may reduce paging.
The garbage collector can also mark the array’s memory as in use in a single step, whereas it must follow the references to class objects separately.
In practice, however, the differences are so small that you should not use performance to decide which approach to use. Usually, you are best off picking the method that makes the most logical sense, and not worrying too much about the slight performance difference.

Heap and Stack Performance

Visual Basic programs allocate variables from two pools of memory called the stack and the heap. Programs take memory for value types (such as integers and dates) from the stack.

Space for reference types comes from the heap. More than one reference can point to the same chunk of memory allocated on the heap. That makes garbage collection and other heap-management issues more complex than using the stack, so using the heap is generally slower than using the stack.

Because structures are value types and classes are reference types, structures are allocated on the stack and class objects are allocated on the heap. That makes structures faster than classes. The exact difference for a particular program depends on the application.

Note that arrays are themselves reference types, so all arrays are allocated from the heap whether they contain structures or references to class objects. The memory for an array of structures is allocated all at once, however, so there is still some benefit to using structures. All the memory in an array of structures is contiguous, so the program can access its elements more quickly than it would if the memory were scattered throughout the heap.

Object Assignment

When you assign one reference type variable to another, you make a new reference to an existing object. When you are finished, the two variables point to the same object. If you change the object’s fields using one variable, the fields shown by the other are also changed.

In contrast, if you set one value type variable equal to another, Visual Basic copies the data from one to the other. If you later change the fields in one object, the fields in the other remain unchanged. Figure 23-3 illustrates the difference for classes and structures.

FIGURE 23-3: Assigning one class reference to another makes them both point to the same object. Assigning one structure variable to another makes a new copy of the data.

image

Example program StructuresAndClasses uses the following code to demonstrate this difference:

Dim cperson1 As New CPerson
Dim cperson2 As CPerson
cperson1.FirstName = "Alice"
cperson2 = cperson1
cperson2.FirstName = "Ben"
MessageBox.Show(cperson1.FirstName & vbCrLf & cperson2.FirstName)
 
Dim sperson1 As New SPerson
Dim sperson2 As SPerson
sperson1.FirstName = "Alice"
sperson2 = sperson1
sperson2.FirstName = "Ben"
MessageBox.Show(sperson1.FirstName & vbCrLf & sperson2.FirstName)

The code creates a CPerson class object and sets its first name value. It then assigns another CPerson variable to the same object. Because CPerson is a class, the two variables refer to the same piece of memory so when the code sets the new variable’s first name value it overwrites the previous variable’s first name value. The message box displays the name Ben twice.

The code performs the same steps again but this time it uses structure variables instead of class variables. The code makes an SPerson structure and sets its first name value. When it sets the second SPerson variable equal to the first one, that makes a copy of the structure. Now when the code sets the second variable’s first name to Ben, it does not overwrite the previous variable’s first name value. The message box displays the names Alice and Ben.

Parameter Passing

When you pass a parameter to a function or subroutine, you can pass it by reference using the ByRef keyword or by value using the ByVal keyword. If you pass a parameter by reference, any changes that the routine makes are reflected in the original parameter passed into the routine.

For example, consider the following code.

Public Sub TestByRef()
    Dim i As Integer = 1
        
    PassByVal(i)
    MessageBox.Show(i.ToString) ' i = 1.
        
    PassByRef(i)
    MessageBox.Show(i.ToString) ' i = 2.
End Sub
        
Public Sub PassByVal(ByVal the_value As Integer)
    the_value *= 2
End Sub
        
Public Sub PassByRef(ByRef the_value As Integer)
    the_value *= 2
End Sub

Subroutine TestByRef creates an integer named i and sets its value to 1. It then calls subroutine PassByVal. That routine declares its parameter with the ByVal keyword, so i is passed by value. PassByVal multiplies its parameter by 2 and ends. Because the parameter was declared ByVal, the original variable i is unchanged, so the message box displays the value 1.

Next the program calls subroutine PassByRef, passing it the variable i. Subroutine PassByRef declares its parameter with the ByRef keyword, so a reference to the variable is passed into the routine. PassByRef doubles its parameter and ends. Because the parameter is declared with the ByRef keyword, the value of variable i is modified so the message box displays the value 2.

When you work with class references and structures, you must think a bit harder about how ByRef and ByVal work. There are four possible combinations: class ByVal, structure ByVal, class ByRef, and structure ByRef.

If you pass a class reference to a routine by value, the routine receives a copy of the reference. If it changes the reference (perhaps making it point to a new object), the original reference passed into the routine remains unchanged. It still points to the same object it did when it was passed to the routine. However, the routine can change the values in the object to which the reference points. If the reference points to a Person object, the routine can change the object’s FirstName, LastName, and other fields. It cannot change the reference itself to make it point to a different Person object, but it can change the object’s data.

In contrast, suppose that you pass a structure into a routine by value. In that case, the routine receives a copy of the entire structure. The routine can change the values contained in its copy of the structure, but the original structure’s values remain unchanged. It cannot change the original structure’s fields the way it could if the parameter were a reference type.

If you pass a class reference variable by reference, the routine can not only modify the values in the reference’s object but also make the reference point to a different object. For example, the routine could use the New keyword to make the variable point to a completely new object.

If you pass a structure by reference, the routine receives a pointer to the structure’s data. If it changes the structure’s data, the fields in the original variable passed into the routine are modified. (The result is similar to what happens if you pass a class reference by value.)

In addition to these differences in behavior, passing class references and structures by reference or by value can make differences in performance. When you pass a reference to data, Visual Basic only needs to send the routine a 4-byte value. If you pass a structure into a routine by value, Visual Basic must duplicate the entire structure, so the routine can use its own copy. If the structure is very large, that may take a little extra time.

Boxing and Unboxing

Visual Basic allows a program to treat any variable as an object. For example, a collection class stores objects. If you add a simple value type such as an Integer to a collection, Visual Basic wraps the Integer in an object and adds that object to the collection.

The process of wrapping the Integer in an object is called boxing. Later, if you need to use the Integer as a value type again, the program unboxes it. Because structures are value types, the program must box and unbox them whenever it treats them as objects, and that adds some extra overhead.

Some operations that require boxing and possibly unboxing include assigning a structure to an Object variable, passing a structure to a routine that takes an Object as a parameter, or adding a structure to a collection class. Note that this last operation includes adding a structure to a collection used by a control or other object. For example, adding a structure to a ListBox control’s Items collection requires boxing.

Note that arrays are themselves reference types, so treating an array as an object doesn’t require boxing.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.229.92