Conversions
When a class derives from another class, it automatically inherits all the members of the base class. As a result, a derived class can always be safely converted to one of its base classes. For example:
Class Person Public Name As String Public Address As String Public City As String Public State As String Public ZIP As String End Class Class Employee Inherits Person Public Salary As Integer End Class Module Test Sub Main() Dim p As Person = New Employee() p.Name = "John Doe" End Sub End Module
In this example, the Framework can allow an instance of Customer to be assigned to a variable of type Person because it knows that a Customer is also a Person. Thus, a Customer can be treated like a Person, and the fields that Customer inherits from Person can be changed. If the preceding example had tried to access fields that were specific to Customer or Employee, however, an error would be given because when an instance is viewed as as a Person, only the members defined by Person can be used, as the following example illustrates.
Module Test Sub Main() Dim p As Person p = New Customer() ' Error: CustomerID is not a member of Person p.CustomerID = 10 p = New Employee() ' Error: Salary is not a member of Person p.Salary = 34923.23 End Sub End Module
Conversely, an instance of a base class can be converted to a derived class, but the conversion is not always guaranteed to succeed. A variable typed as Person could contain an instance of the Employee class, but it could also contain an instance of some other type.
Module Test Sub Main() Dim p As Person = New Employee() ' Error: Can't convert Employee to Customer Dim c As Customer = CType(p, Customer) End Sub End Module
The Customer class also inherits from Person, so it can be converted to Person. However, the instance stored in the variable is still a Customer; as such, it cannot be treated as an instance of the Employee class. In this case, the Framework will throw a System.InvalidCastException exception at runtime when the conversion is executed.
The important principle to keep in mind is that when you create an instance of a class, it always stays that type, no matter what it is converted to. A Customer class converted to Person is still a Customer, even if the additional fields that Customer adds to the Person class are not visible. The power of inheritance is that it allows code to be written that works on the most general type in a hierarchy, which means that code can be written very broadly. For example, a method that takes a Person and prints the name and address of that Person can take a Customer or an Employee, instead of having to write separate methods for Customer and Employee.
Module Test Sub PrintAddress(ByVal p As Person) Console.WriteLine(p.Name) Console.WriteLine(p.Address) Console.WriteLine(p.City & ", " & p.State & " " & p.ZIP) End Sub Sub Main() Dim c As Customer Dim e As Employee PrintAddress(c) PrintAddress(e) End Sub End Module
Array Covariance
Inheritance conversions extend to arrays as well. In general, an array of a particular type cannot be converted to any other type, because the array storage is allocated based on the type of the array. For example, it is not possible to covert a one-dimensional array of Integer to a one-dimensional array of Long, because Integer and Long do not have the same size. Thus, an array of ten Integer values could not hold ten Long values within the same space. However, because classes are reference types, the size of an array that holds ten Customer instances is the same size as an array that holds ten Employee instances. Thus, an array of a reference type may be converted to an array of another reference type, provided that the element types themselves convert to one another. For example:
Module Test Sub Main() Dim Customers(9) As Customer Dim People() As Person For Index As Integer = 0 To 9 Customers(Index) = New Customer() Next Index People = Customers For Index As Integer = 0 To 9 People(Index).Name = "John Doe" Next Index End Sub End Module
The one-dimensional array of Customer can be converted to a one-dimensional array of Person because a Customer can be converted to a Person.
This conversion behavior of arrays is called covariance. Covariance is useful in the same way that inheritance is.
Module Test Sub SetCityState(ByVal People() As Person, ByVal City As String, _ ByVal State As String) For Each Person As Person In People Person.City = City Person.State = State Next Person End Sub Sub Main() Dim Employees(9) As Employee ... SetCityState(Employees, "Akron", "OH") End Sub End Module
In this example, the base class Person provides a method that will set the City and State fields for an array of Person instances. The Main method can pass an array of Employee instances to the method because an array of Employee can be converted to an array of Person. One important thing to note, though, is that even though the array has been converted to an array of Person, it still can only hold Employee instances. Thus, an attempt to assign any other type into the array will cause a System.InvalidCastException exception. For example:
Module Test Sub FillArray(ByVal People() As Person) For Index As Integer = 0 To People.Length -1 People(Index) = New Person() Next Index End Sub Sub Main() Dim Employees(9) As Employee FillArray(Employees) End Sub End Module
This example will throw an exception because the array being passed in to FillArray is an array of Employee, not Person, so only Employee instances can be stored in the array.