2. Classes

 

Visual Basic has never been considered to be a clean programming language. This became a Gordian knot for Microsoft and began brewing trouble. However, in spite of this setback, amazingly, no other product has sold more copies than Visual Basic in the history of the computing world. Thus, Microsoft has no choice but to retain the heart and soul of Visual Basic, and simultaneously, embellish it with the latest features available in language technology. This forms the genesis of Visual Basic.Net. Visual Basic .Net is primarily an extension of the Visual Basic programming language that is shipped with the Visual Basic product.

 

In Visual Basic.Net, which is the improved version of Visual Basic, we can replace the word 'module' with the word 'Class'. Together with this modification, one more change is required, i.e. the word 'Shared' has to be added to the Sub Main.  If the main subroutine is not amended to 'shared', the following error crops up:

 

Error

vbc : error BC30737: No accessible 'Main' method with an appropriate signature was found in 'a'.

 

a.vb

Class zzz

Shared Sub Main

System.Console.WriteLine("hi")

End Sub

End Class

 

Output

hi

 

Now, when we compile and run the program, the code in Main gets called, displaying the word "hi". A class is an entity like a module, which carries code and variables.

 

a.vb

Class zzz

Shared Sub Main

abc

End Sub

Shared sub abc

System.Console.WriteLine("in abc")

end sub

End Class

 

Output

in abc

 

The above example has a subroutine called abc, with the word 'Shared' added to it. If the word 'Shared' is omitted, the compiler generates the following error:

 

Error

c:\il\a.vb(3) : error BC30369: Cannot refer to an instance member of a class from within a shared method or shared member initializer without an explicit instance of the class.

 

Let us now delve upon what the word 'Shared' signifies.

 

 

 

a.vb

Class zzz

Shared Sub Main

dim a as zzz

a = new zzz

a.abc

pqr

zzz.pqr

End Sub

sub new()

System.Console.WriteLine("in new")

end sub

sub abc

System.Console.WriteLine("in abc")

end sub

shared sub pqr

System.Console.WriteLine("in pqr")

end sub

End Class

 

Output

in new

in abc

in pqr

in pqr

 

The above program has Main and pqr subroutines marked as 'shared', whereas, the others remain unmarked.

 

In Sub Main, we first need to create a variable named 'a' of type 'zzz'. Here, we are not actually creating an object or variable 'a' of type zzz, but merely stating that the variable 'a' looks like the class zzz. This is akin to creating variables of a certain type. Also, we can safely presume that integer, string and long are all classes. The difference is that the Visual Basic.Net compiler is aware of the fact that these classes are data types.

 

zzz is a user-defined datatype, which the compiler is oblivious to. Hence, we need to create an actual instance or occurrence of this datatype. By using the keyword 'new', an instance or an object of type zzz is created. The line a = new zzz creates a new object zzz in memory, and returns a handle that is stored in 'a'. To frame it differently, 'a' represents a fresh zzz object in memory.

 

An object is an instance of a class. Thus, the statement 'DIM i as integer' creates an object i, which is an instance of class integer. For the basic in-built data types such as string, boolean and integer, there is no need to explicitly mention 'new', which is otherwise mandatory for the user-defined types.

 

In Visual Basic.Net, the keyword 'new' first allocates memory for all the class contents, and then, it checks for a sub called 'New'. If the sub 'new' exists, it executes the code present in it. In most other languages, the sub new() is equivalent to a constructor of a class. After the subroutine ends, a zzz object is created and stored in 'a'. The object 'a' can then be used to call the other members in the class.

 

Initially, the abc procedure is called and then, the sub pqr is called twice:

     At the first instance, without the use of the prefix 'a'.

     At the second instance, using the class prefix.

 

The word 'shared' implies that the function can be called without creating an object. Since abc is not shared, we have to create an instance of a zzz object, in order to access it. The pqr sub is marked as 'shared'. Therefore, it does not require an instance of an object to access it.

 

We normally preface a member with the name of the class, which is the default, if not specified expressly. The sub of main also is marked as 'shared'. Therefore, it does not require an instance of the class zzz before it can be used.

 

Prior to venturing further into the concept of Shared, let us anatomize the concept of a constructor.

 

a.vb

Class zzz

Shared Sub Main

dim a as zzz

a = new zzz

End Sub

sub new(i as integer)

System.Console.WriteLine("in new {0}", i)

end sub

End Class

 

Error

c:\il\a.vb(4) : error BC30455: Argument not specified for parameter 'i' of 'Public Sub New(i As Integer)'.

 

Earlier, the constructor did not accept any parameters. Thus, we were able to call it without any parameters. In the above program, we have a constructor that expects one parameter of type integer. However, in the process of creating an instance of the object zzz, we have not furnished any parameters to 'new'. This results in an error.

 

a.vb

Class zzz

Shared Sub Main

dim a as zzz

a = new zzz(10)

End Sub

sub new(i as integer)

System.Console.WriteLine("in new {0}", i)

end sub

End Class

 

Output

in new 10

 

We have now redressed the above error by passing a parameter to the 'new' statement. So, when the constructor gets called, the value received in the parameter i is 10. This value is displayed on the Console. A constructor can be equipped to accept as many parameters as we wish to supply it.

 

 

a.vb

Class zzz

Shared Sub Main

dim a as zzz

a = new zzz(10)

a.new(10)

End Sub

sub new(i as integer)

System.Console.WriteLine("in new {0}", i)

end sub

End Class

 

Error

c:\il\a.vb(5) : error BC30282: Constructor call is valid only as the first statement in an instance constructor.

 

Unlike a subroutine, a new constructor cannot be called explicitly. An error is generated in the above program, since we are attempting to call a constructor by itself. Thus, a constructor gets called automatically only when the object is created, and not otherwise. Further, it cannot be called manually.

 

a.vb

Class zzz

Shared Sub Main

dim a,b as zzz

a = new zzz(10)

b = new zzz()

End Sub

sub new(i as integer)

System.Console.WriteLine("in new {0}", i)

end sub

sub new()

System.Console.WriteLine("in new ")

end sub

End Class

 

Output

in new 10

in new

We can have innumerable constructors or 'new' statements in the program, provided each is assigned different parameters. The above program has two new subroutines, the first one accepts a single integer parameter, while the second one does not take any parameters. This program is perfectly valid.

 

The concept of using the same function name with different parameters is called 'function overloading' or 'sub overloading'.

 

Now, we present another example on 'function overloading'.

 

a.vb

Class zzz

Shared Sub Main

abc()

abc(10)

abc("hi")

End Sub

shared sub abc(i as integer)

System.Console.WriteLine("in abc {0}", i)

end sub

shared sub abc()

System.Console.WriteLine("in abc ")

end sub

shared sub abc(k as string)

System.Console.WriteLine("in abc {0}", k)

end sub

End Class

 

Output

in abc

in abc 10

in abc hi

 

In the above example, we have three subs with the same name 'abc', but each of them has different parameters. Out of the three, two subs have the same number of parameters, but their data types are distinct. 

 

 

This is permitted, since the name of a function in Visual Basic.Net does not consist of the name alone, but is composed of the name and the data type of each parameter. Thus, the name of the first sub abc that accepts an integer parameter, could be represented by 'abci', where i is the data type of the parameter. The last sub could be represented by 'abcs', where s stands for the string type of the parameter. This naming concept initiates uniqueness in the function names.

 

This concept is known as 'name mangling', where the signature of the function depends upon both, the name of the parameters and their datatypes.

 

Now, we present yet another example on constructors to make the concept of constructors crystal clear.

 

a.vb

Class zzz

Shared Sub Main

dim a as zzz

a = new zzz()

End Sub

End Class

 

a.vb

Class zzz

Shared Sub Main

dim a,b as zzz

b = new zzz()

End Sub

sub new(i as integer)

System.Console.WriteLine("in new {0}", i)

end sub

End Class

 

Error

c:\il\a.vb(4) : error BC30455: Argument not specified for parameter 'i' of 'Public Sub New(i As Integer)'.

 

 

Let us comprehend the concept of constructors by examining the above two examples. The first example compiles without any errors, despite containing no constructor code.

 

Visual Basic.Net is not complaining for the reason that, when the program does not contain any constructors, the complier introduces one of its own, as follows:

 

Sub new

End sub

 

Thus, when a constructor is not created explicitly, the compiler creates one for us. This constructor does not accept any parameters, nor does it do anything. However, if we include even a single constructor, this complimentary constructor is carted-off or taken away. Thus, in any situation, there would always be at least one constructor present in the code.

 

In the second example, a constructor with one parameter is present. Therefore, the free constructor with no parameters, which would have otherwise been generated is not present. So, creating an instance of the zzz object by calling the constructor that accepts no parameters, generate an error.

 

To summarize, when no constructors are present in the class, a constructor that does not accept any parameters, is automatically generated. However, with the insertion of even a single constructor, the free constructor is not created. In such a situation, each and every new variant of the constructor has to be added manually.

 

a.vb

Class zzz

dim i as integer

Shared Sub Main

dim a as zzz

a = new zzz

a.i = 10

a.abc

a.pqr

End Sub

Sub abc

System.Console.WriteLine(i)

i = 20

End Sub

Sub pqr

System.Console.WriteLine(i)

End Sub

End Class

 

Output

10

20

 

The above example contains an instance variable i. It is referred to as an instance variable since unlike 'a', it is not created in a sub, but is created outside the subs and within the class.

 

The lifetime of an object such as 'a' endures as long as the sub is active; once the sub concludes executing its code, all the variables that have been declared in it, lose their values or are considered non-existent thereafter. The visibility of such variables is restricted to the function or sub that they are created in. Thus, the object 'a' is visible only within the sub Main and not in the other subs, such as abc.

 

On the other hand, the lifetime of the variable i is linked to the life-span of the program. Since it is declared outside all the subs, it is visible in all the subs within the class.

 

In main, the value of i is set to 10. It is prefaced with the name of the object, since it is not shared. Then, the sub abc is summoned, which displays the value of 10 and changes it to 20.  Next, when the subroutine pqr is called, the value of the instance variable is 20. This is for the reason that, only a single copy of i is created in memory, when the zzz object is created. Thus, both the subs, viz. abc and pqr refer to this same instance variable i.

 

a.vb

Class zzz

dim j as integer

shared dim k as integer

Shared Sub Main

dim a,b as zzz

a = new zzz(10)

a.abc(100)

b = new zzz(20)

b.abc(200)

End Sub

sub new(i as integer)

System.Console.WriteLine("in new {0} {1} {2}", i , j , k)

j = i

k = i

System.Console.WriteLine("in new {0} {1} {2}", i , j , k)

end sub

sub abc(p as integer)

System.Console.WriteLine("in abc {0} {1}",  j , k)

k = p

j = p

end sub

End Class

 

Output

in new 10 0 0

in new 10 10 10

in abc 10 10

in new 20 0 100

in new 20 20 20

in abc 20 20

 

The above example reinforces the dissimilarities between a shared variable and a non-shared variable. The words 'variable' and 'object' may be used interchangeably. In the manner akin, what is pertinent to a sub is also applicable to a function, unless otherwise specified.

 

In the above program, the class zzz has two variables:

     j - which is an instance variable.

     k - which is a shared variable.

 

 

 

The basic distinction between the two is as follows:

(a) A shared variable belongs to a class, which implies that each time a new instance of the class is created, the shared variable does not get re-created. To access the shared variable, the name of the class is used, since there is only a single shared variable per class.

 

(b) An instance variable gets created, each time that a new instance of a class is created. Therefore, if an object is instantiated on 20 counts, it will result in the creation of 20 new copies of the instance variable in memory.

 

In Main, two local variables a and b, of type zzz are created. Since they are local, they have a very short life span. While creating the object 'a', the constructor for the object zzz is assigned a value of 10. Therefore, in the constructor, the value of i becomes 10, whereas, both j and k have a value of 0. If the instance variables are not explicitly initialised, the system initialises them to a value of zero.

 

The constructor assigns the value contained in i, i.e. 10, to both the variables j and k. Therefore, in the second round, the WriteLine function displays the values of all three variables as 10. The sub abc is then called with a parameter of 100. Here, the values of variables j and k remain 10, as has been displayed by the WriteLine function. We now re-initialize both the variables j and k to 100, and then, quit out of the sub.

 

The next statement in the Main function creates a new instance of zzz, wherein the constructor is assigned a value of 20. The WriteLine function prints the values of i, j and k as 20, 0 and 100, respectively. The instance variable j has a value of 0, as it has been freshly created. Shared variables are not affected by the 'new' keyword. Thus, the variable k retains its original value of 100, which was set in the abc function. The second WriteLine function in the constructor displays the newly assigned value of j and k, i.e. 20.

 

The abc function is called once again using the object b. The variable j now displays the value of 20, since the constructor of the 'b' object in zzz had initialized it to 20. This variable is then assigned a value of 200. However, the second copy of j, which belongs to the object 'b', retains its value of 20, since it has nothing to do with the variable j from the object 'a'.

 

To summarize what we have been harping on over and over, an instance variable belongs to an object, whereas, a shared variable belongs to a class. This is indubitably evident from the manner in which these variables are accessed. We are taking the trouble of explaining all the above code and concepts, in order that you can discern even the most diminutive of the Visual Basic .Net programs, generated by Visual Studio.Net.

 

The approach that we have pursued is that we first explain the concepts using the Visual Basic.Net compiler, and then we implement them in Visual Studio .Net.

 

Namespaces

 

a.vb

Class zzz

Shared Sub Main

dim a as yyy

a = new yyy

a.abc

End Sub

End Class

Class yyy

sub abc

System.Console.WriteLine("abc")

end sub

end class

 

Output

abc

 

The above example lucidly establishes that a Visual Basic.Net program can contain innumerable classes, as long as one of these classes contains the Sub of Main. The above program has two classes named zzz and yyy. In the class zzz, 'a' is declared to be an object of type yyy. After having created the object, the function abc is called from it.

You may wonder as to what is the big deal here, since the program runs in a manner akin to any other program. Although we accede to the fact that the program is no different from the earlier ones, nonetheless, we would still like to forge ahead with it.

 

The class Console has a shared function called WriteLine, which is used to display strings. So, nothing holds us back from creating a class called Console, in the fashion similar to the one used to create the class yyy. Then, in the class, we can create our own function named WriteLine.

 

This is perfectly within the realms of possibility, since we now know how to create a class and a function within the class. However, there is bound to be some confusion because when the user enters the statement 'Console.WriteLine', the framework would be in a dilemma whether to call the function created by us or the one supplied by Microsoft.

 

Microsoft seems to have already foreseen this predicament, and therefore, to avert such name clashes from occurring, the big guys or Visual Basic.Net ordains that every class should be a part of a name or a namespace. The next example demonstrates the implementation of namespaces.

 

a.vb

Class zzz

Shared Sub Main

dim a as nnn.yyy

a = new nnn.yyy

a.abc

End Sub

End Class

Namespace nnn

Class yyy

sub abc

System.Console.WriteLine("abc")

end sub

end class

End Namespace

 

Output

abc

 

We have effected a minor amendment to the class yyy. A new word, i.e. Namespace has been introduced above the class yyy, and the name assigned to it is 'nnn'. As a rule, everything in Visual Basic.Net must terminate with the word End. Therefore, the Namespace also ends with the words 'End Namespace'.

 

With the introduction of a namespace, the name of the class is no longer just yyy, but is now 'nnn.yyy'. The syntax for the class name now changes to the following: 

     name of the namespace followed by a dot, and finally, followed by the class name.

 

Thus, whenever we need to refer to the class yyy, the reference to be employed is nnn.yyy. If we omit the namespace 'nnn' from the DIM statement, the following error is generated:

 

Error

c:\il\a.vb(3) : error BC30002: Type 'yyy' is not defined.

 

a.vb

Class zzz

Shared Sub Main

dim a as aaa.nnn.yyy

a = new aaa.nnn.yyy

a.abc

End Sub

End Class

Namespace aaa

Namespace nnn

Class yyy

sub abc

System.Console.WriteLine("abc")

end sub

end class

End Namespace

End Namespace

 

Output

abc

 

In the above example, two namespaces have been added to the class yyy, viz. aaa and nnn. Thus, the name of the class now becomes aaa.nnn.yyy. The namespace statement can be re-written as 'Namespace aaa.nnn'.

 

a.vb

Class zzz

Shared Sub Main

aaa.nnn.yyy.abc

End Sub

End Class

Namespace aaa.nnn

Class yyy

shared sub abc

System.Console.WriteLine("abc")

end sub

end class

End Namespace

 

Output

abc

 

In this example, the abc function is marked as 'shared'. Here, no object of type yyy has been created. Thus, to call the abc function, the name of the class 'yyy.abc' is used. Now, with the inclusion of the namespace tag above the class, the only way to call this function is by using its full name, i.e. aaa.nnn.yyy.abc.

 

This syntax bears a resemblance to the commonly used System.Console.WriteLine. Thus, a sub or a function has to be read from right to left as follows:

  The rightmost entity 'WriteLine' or 'abc' is the name of the method.

  The next entry on the left, i.e. 'Console' or 'yyy' is the name of the class.

  The next entry on the left, i.e. 'System' or 'nnn' is the name of the namespace entity.

The Console class belongs to the System namespace. The WriteLine function is a shared function in this class. In the case of methods that are not 'shared', the object name has to be expressly specified to access the method.

 

Namespaces influence only the class names and not the object names. By employing namespaces, both similar as well as disparate classes can be placed under a single heading. Microsoft has politely reserved the use of the 'System' namespace. Thus, no developer can ever create a namespace by that name, thereby avoiding any clashes with Microsoft's set of entities.

 

Classes sharing the same names can be placed under different namespaces without any confusion. However, the problem with using these namespaces is that they are extremely lengthy. The next program provides a solution to this poser.

 

a.vb

Imports aaa.nnn

Class zzz

Shared Sub Main

dim a as yyy

a = new yyy

a.abc

End Sub

End Class

Namespace aaa.nnn

Class yyy

sub abc

System.Console.WriteLine("abc")

end sub

end class

End Namespace

 

Output

abc

 

The program begins with the newly introduced keyword of 'Imports', followed by the name of the namespace, i.e. aaa.nnn. This statement does not introduce any new code, as its sole task is to add the namespace aaa.nnn to every class, thereby circumventing errors.

 

For instance, the Visual Basic.Net compiler would have thrown an error on encountering the class yyy in the DIM statement, since there is no class called yyy. However, on catching sight of the 'import' keyword, it adds the namespace to the name of the class, resulting in the name aaa.nnn.yyy. As there already exists a class by this name, the Visual Basic.Net compiler does not protest.

 

In case the error still persists, it takes the next set of Imports statement, and attempts to seek a match. Only when all the Imports fail to find a match, a "not found class" error is thrown. Effectively, the imports statement is like a short form, which when introduced, eliminates the need for mentioning the namespace on every occurrence of the class.

 

Bear in mind that it is the namespace, and not the name of the class, which is permitted after the Imports keyword.

 

a.vb

Class zzz

Shared Sub Main

dim a as yyy

a = new yyy

a.abc

a.pqr

End Sub

End Class

Class yyy

sub abc

System.Console.WriteLine("yyy abc")

end sub

end class

Class xxx

sub pqr

System.Console.WriteLine("xxx pqr")

end sub

end class

 

 

Error

c:\il\a.vb(6) : error BC30456: 'pqr' is not a member of 'yyy'.

 

The above example has three classes, viz. xxx, yyy and zzz. The class xxx has the sub pqr, the class yyy has the sub abc, while the class zzz has the sub Main.

 

In Main, an object 'a' is created to be an instance of the class yyy. Thus, the sub abc can now be called off it. However, calling the sub pqr using the object 'a' results in an error, as the class yyy does not contain pqr. The class xxx contains the sub of pqr. Thus, a class is a self-contained unit wherein, the entities belonging to one class cannot be accessed by another class.

 

a.vb

Class zzz

Shared Sub Main

dim a as yyy

a = new yyy

a.abc

a.pqr

End Sub

End Class

Class yyy

Inherits  xxx

sub abc

System.Console.WriteLine("yyy abc")

end sub

end class

Class xxx

sub pqr

System.Console.WriteLine("xxx pqr")

end sub

end class

 

Output

yyy abc

xxx pqr

 

 

In the above program, we have merely added the word 'Inherits' to the name of a class xxx, on the line below the class yyy. With this new induction, all the entities present in the class xxx, now belong to the class yyy too. Thus, all the code and instance variables that are present in the class xxx, can now be used by the yyy object 'a'.

 

This is one of the most salient concepts in the world of object oriented programming, wherein, a class such as yyy can derive itself from a base class like xxx. And by virtue of this, it can reuse code that is present in this base class. Programmers are very often mentally fine-tuned to write code in this fashion.

 

The code is never to be written from a scratch. Instead, it is derived from a class that already has code present in it. By using 'inherits', the derived class simply inherits everything from the base class.

 

Now, insert the following two lines on a single line as in.

 

Class yyy

Inherits  xxx

to

Class yyy Inherits  xxx

 

This action generates the following error:

 

Error

c:\il\a.vb(9) : error BC30205: End of statement expected.

 

Even though Visual Basic.Net is known to be an exceedingly flexible language, it still requires us to adhere to certain rules. Thus, we have no choice but to place the word 'Inherits' on a separate line. The indentation is for the sake of neatness, and for good luck of course!

 

a.vb

Class zzz

Shared Sub Main

dim a as yyy

a = new yyy

End Sub

End Class

Class yyy

Inherits  xxx

sub new

System.Console.WriteLine("new yyy")

end sub

end class

Class xxx

sub new

System.Console.WriteLine("new xxx")

end sub

end class

 

Output

new xxx

new yyy

 

In the above example, the class yyy derives from the base class xxx. Therefore, when an instance of class yyy is created, two constructors are called, one from the class xxx, and the other from the class yyy, in the prescribed sequence. This occurs because the class yyy is also made up of the class xxx. Thus, while an instance of a yyy object is being created, two objects are created in memory: a xxx object, followed by a yyy object.

 

During the creation of these two objects in memory, the constructors of these classes get called. A constructor, as you may recall, is called when an object is created. The constructor of the base class, i.e. xxx is always called first, followed by the constructor of the derived class yyy.

 

a.vb

Class zzz

Shared Sub Main

dim a as yyy

a = new yyy

End Sub

End Class

Class yyy

Inherits  xxx

sub new

mybase.New

System.Console.WriteLine("new yyy")

end sub

end class

Class xxx

sub new

System.Console.WriteLine("new xxx")

end sub

end class

 

Output

new xxx

new yyy

 

Yet another line has been added to the constructor of the class yyy, i.e. mybase.New. Despite our not having created any variable or object called mybase, no error is generated. This is because, every method or function or sub is provided with a free object called mybase, which is a handle to the base class.

 

By specifying mybase.New, the constructor of the base class gets called. No specific reason can be attributed to this, but most code written in the Visual Basic.Net world, calls the constructor of the base class in the above-mentioned manner. The mybase object is used to access members of the base class.

 

a.vb

Class zzz

Shared Sub Main

dim a as yyy

a = new yyy

End Sub

End Class

Class yyy

dim i as integer

sub new

Me.i = 10

System.Console.WriteLine("new yyy {0}" , Me.i)

end sub

end class

 

Output

new yyy 10

 

Obtaining a free ride in life has never been too easy. In the Visual Basic.Net world, not only do we get a free mybase object, but also acquire another object called Me. The Me object is used to refer to itself, while the mybase object is used to refer to the base class. In the above example, whether we write Me.i or i, it would mean the same thing.

 

a.vb

Class zzz

Shared Sub Main

dim a as yyy

a = new yyy(100)

a.abc

End Sub

End Class

Class yyy

dim i as integer = 10

sub new(i as integer)

System.Console.WriteLine("new yyy {0} {1}" , Me.i , i)

Me.i = i

end sub

sub abc

System.Console.WriteLine("new yyy {0} {1}" , Me.i , i)

end sub

end class

 

Output

new yyy 10 100

new yyy 100 100

 

The utility of the reserved word Me is evident in the above example, where the class yyy has an instance variable named i, and the parameter to the constructor is also named i.

 

In the class zzz, 'a' is created as an object to yyy, by assigning a value of 100 to the constructor. Doing so would load the yyy object in memory, where the first line is a DIM statement. The DIM statement utilizes an 'equal to' sign to initialize the variable during its creation. Thus, the instance variable i is initialized to the value of 10.

 

Thereafter, the constructor of class yyy is called, where the WriteLine function displays the value of i. The i being referred to here is the parameter i in the constructor, and not the instance variable i. This is because the parameters and local variables get higher preference in a function.

 

However, using Me.i in the constructor would refer to the instance variable and not to the parameter. The statement Me.i = i, would initialize the instance variable i to the value stored in the parameter i. In the sub abc, i and Me.i will always refer to the instance variable, since there is no parameter named i.

 

Thus, the keyword Me proves to be of great utility, when there is an instance variable and a local variable, both having the same name.

 

a.vb

Class zzz

Shared Sub Main

dim a as yyy

a = new yyy

End Sub

End Class

Class yyy

Inherits  xxx

sub new

mybase.New

System.Console.WriteLine("new yyy")

end sub

end class

Class xxx

Inherits ppp

sub new

System.Console.WriteLine("new xxx")

end sub

end class

Class ppp

sub new

System.Console.WriteLine("new ppp")

end sub

end class

 

Output

new ppp

new xxx

new yyy

 

In the above program, the class ppp is a self-contained unit, which is not derived from any other class. Then, the class xxx is derived from class ppp. Hold your horses! There is more to it. One more class yyy is then derived from the class xxx. As a result, the class yyy is directly/indirectly derived from the two classes xxx and ppp.

 

Now, creating an instance of class yyy, would lead to the creation of three objects in memory, viz. xxx, yyy and ppp. The sequence is important, since the base class constructor always gets called first.

 

Thus, the ppp constructor gets called first, the xxx class gets called next, and finally, it is the yyy class that gets called. The abovementioned rules apply, irrespective of the number of classes that we derive from.