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.