The Three Pillars of OOP

parentpitaΛογισμικό & κατασκευή λογ/κού

18 Νοε 2013 (πριν από 3 χρόνια και 6 μήνες)

74 εμφανίσεις

The
Three
Pillars
of OOP
(Object Oriented Programming, that is)
by Michael F. Lynch PhD
Version 1.0 – R
eleased September 17, 2007
The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
1
Introduction
This article is an attempt to introduce most of the concepts involved in Object Oriented

Programming (OOP), an important aspect of building modern, scalable and maintainable.

It does so by also introducing how OOP is done inside of C# and .NET.
OOP, by itself, is only part of the Object-Oriented picture; there are also Object Oriented

Analysis (OOA) and Object Oriented Design (OOD). While this article is mostly about

Object Oriented Programming, it's useful to look at OOA and OOD to see how it all fits

together.
The use of the words Analysis and Design refer to various stages in the development of

any large system, whether hardware, software, or both, and these terms have a long history

in engineering practice. What follows here is a highly simplified view of what goes on

during these stages of development.
During the Analysis Phase, analysts look at the problem to be solved
in terms of the problem
,

seeking to understand the nature and complexity of the problem described using the

established language and jargon from within the problem domain itself. During this phase,

little thought should be given on specifying the nature of the solution; that is performed

during the Design Phase. Instead, detailed conceptual views of the problem space are

generated and, from that, a set of requirements for the system to be built is generated.
During the Design Phase, the designers and engineers begin to develop what will become

the "solution", that is, the system to be built, which addresses the requirements uncovered

during the earlier analysis of the problem. The solution generally proceeds from big-block

top-level pictures down through ever-more detailed descriptions until actual

implementation can begin.
The above description seems to imply that events proceed in a serial fashion from Analysis

to Requirements to Top Level Design to Detailed Design to Implementation. In fact, at

one time, it was believed by many (in particular the Department of Defense) that this is

how software ought to be built. This was called the "Waterfall Mode", and these days it has

been completely discredited.
What happens in the real world is that requirements, competitive pressures, technologies,

personnel, etc. etc. are constantly shifting, and it is impossible to nail
down
anything long

enough to be able to build an implementation that doesn't inevitably involve considerable

rework in the face of ever-shifting requirements. This is the situation today, and new

software development methodologies have been developed, for example, Agile and Scrum,

which do a much better job of letting a team of developers build complex systems in

today's dynamic environments and despite ever-changing requirements.
So where do OOA/OOD/OOP fit into this picture? They are, most of all, tools for

The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
2
helping to wrestle complex systems to the ground so that they can be clearly understood

and developed. Without methodologies like Agile and Scrum and tools like

OOA/OOD/OOP, building large systems becomes hopelessly complex and the chances

for success quite risky.
Object Oriented Analysis (OOA), then, is part of the analysis phase in which we look at the

problem space in terms of the problem space. If we were out to build some sort of

medical information system, we would probably uncover, as part of our analysis, the notion

of "patient". This leads quickly to the idea that there is going to be a need to retain certain

pieces of information about the patient, like the patient's name and birth date. But at this

stage we do not worry about how these are going to get represented in the final system,

since that decision should be deferred until later. Say, however, that you were actually

building a veterinary system. Now, besides name and birth date, we will likely also need to

keep information about
the patient, like
its owner and what species it is. After all, caring for

a gecko is probably going to be quite different than caring for a dolphin, and the

subsequent analysis work will no doubt reveal substantial complexity in all the subtleties of

caring for many different kinds of animals.
But what is uncovered during OOA are
classes
, which is the first notion we need to consider

doing Object-Oriented development. During the analysis phase, when we specify classes,

we seek to identify things from the problem space all the things we need to represent as

classes. “Things”, here, can mean physical objects in the world (like "patients" or "engine

blocks"), events (like the occasion of a patient visiting a doctor), or relationships (like a

doctor-patient relationship, with its attendant details).
But during analysis, these are described in terms of the problem, so information about a

patient or whatever is mostly descriptive, and not concerned with specific implementation

details. As the process moves through design and on to implementation, these details get

increasingly filled in.
During the design phase
, the many classes identified during analysis are transformed into

classes with far more rigorous specifications. For the most part, a class identified during

analysis will go over more or less unchanged into the design. However, it often happens

that a class
identified during analysis needs to be defined better for design. Perhaps it is too

big or too busy or made of of simpler parts that should in themselves be classes. In these

cases, the class gets “unwound” or “decomposed” into more clearly defined and clearly

refined classes.
Many tools have been developed over the years to make this process more rigorous and

formal, not to mention less painful. Use Case Analysis and Use Case Designs, Unified

Modeling Language (UML), Entity-Relationship Diagrams (ERDs), and so forth, are part

of the arsenal of tools used to help understand and develop really complex systems.
When the design phase is complete, a large number of classes will have been identified,

The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
3
each with precisely specified data members and the operations (methods) the class needs to

support to get its work done. When this stage is complete, programming can begin.
OOP – Time To Program
Once you get to the point where it's time to start implementation, most of the class

definitions should already be firmly established as part of the outputs of the design phase.

In each class, you know what data fields it contains, and what methods it supports.
Now it is time to look a little more closely at what a class is, and how we work with it.
Briefly, a
class
is a template for creating
objects
.
What you write as a programmer when

you
design a class is a full class definition.
An
object
is an
instance
of a class. In most programs, y
ou will often have many
instances

(objects) of a given class. There is a distinct difference between class and object, and it is a

good idea to be rather precise in your use of the two terms. For a given class only one

definition, that is, template, can exist. But there is no limit on the number of instances of a

class that get instantiated (unless you deliberately restrict this).
Formally, a
class
is simply a user defined type (UDT) that is composed of data, along with

functions that operate on the data.
Here, “user” can refer to Microsoft, the author of the

huge .NET FCL, .a third-party develop of classes (often called “components”) and even

you, the programmer.
Designing a class is rather different than using the class in a program.
There are two places

where you do OOP:

When you define the classes themselves.

When you create
instances
of a class.
Whatever classes you develop ultimately inherit from ancestor classes supplied to you by the

development environment you are using.
It is with these built-in objects, plus the ones you

develop for your system, where the real work of your system gets done.
In .NET the “boss” object – from which all other objects are derived – is called

System.Object
. As
the “boss” object,
System.Object
is, at the very top of the

.NET class hierarchy. We will see more about this later on.
OOP – Designing Classes
Ideally, the OOD phase uncovered all the details of all the classes you will need to write.

When it comes time to implement the system, the programming will consists of writing

new classes as well as leveraging the thousands of available object classes rather that writing

your own from scratch.
The .NET Framework Class Library (FCL) has over 4000 classes

ready for you to use. The Java development environment is similarly well equipped with

The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
4
thousands of classes. Note that you only will probably ever need to use a hundred or so

(maybe 200), since most of the rest are highly specialized and the need for them rarely

comes up.
If a built-in class does not do quite what you need, you usually create a
descendant
class

from the built-in one that is closest to what you need. In fact, this is most often the most

desirable approach, as we will see later.
In the case of .NET, the classes we build will

descend from more fundamental classes in the FCL. .. in fact you have no choice in the

matter.
The Three Pillars of Object Oriented Programming
The Three Pillars of Object Oriented
Programming are:

Encapsulation

Inheritance

Polymorphism
We begin by looking at Encapsulation.
Encapsulation –
The First Pillar
Very early on, good programmers discovered that they tended to group data

and the

functions that worked on that data – together, yet there was no “metaphor” for binding

data elements to the functions that knew how to work on them.
The Object Oriented

Programming paradigm has been a 30+ year long effort to bring a formal model for

data+code
into being. Encapsulation is thus the resulting First Pillar of OOP.
The class brings together the
data
that belongs to that class along with the
functions
that

know how to work on that data.
In general, you want to hide the internals of your class as

much as possible so that users of your class are protected from misusing it. Another

important reason is so that the internal state of your object is protected from users,

whether inadvertent or malicious! This is what encapsulation is all about.
So classes consist of two parts: data and methods. Whatever data can be stored in a class (it

can be a little or a lot), the class's methods are the means by which users of the class can

work with the data. This leads to our first pillar of OOP:
Encapsulation
.
The data in a class are variously called attributes, fields and properties.

Attributes
usually refer to the class’s state information.

Fields
are completely public data elements.

Properties
are data elements whose access is controlled.
Functions that can work on data in a class are usually called
methods
.
Certain kinds of

functions are called
events
.
The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
5
Collectively both data and functions are called
members
.
In general, you have very fine-grained control over how the members in your class (both

data and methods) are made visible to users of the class (i. e. object instances).
We will see

more about how this works later on.
With encapsulation, we can control read and write access to the member in several

important ways. We can make a data member read-only, write-only (which is rare), or both.

As part of controlling access to data members, we usually want to perform validity checks

when users of class instances try to write a value to a member that’s been granted write

access.

Data members set up this way are usually called
properties
.

We use “gets” and “sets” to access their values.

Data members that are declared
public
(as we shall see) are
usually called
fields
.
As a general principle, it's usually a better idea to arrange to have the data members in any

class you design be properties rather than fields so that you can help ensure that only valid

values are written. With publicly declared fields, you are at the mercy of users of your class

(who are working with instances or objects) to write only
valid values
to the members. This

is not to say that you should never have data members declared
public
; it depends on the

circumstances and context, and you will need to rely on your experience and judgment to

guide you.
We will see a little more about this later on.
An Example in C#
Let's start with a simple example, a class for holding complex numbers. In C#, classes are

declared with the keyword class, followed by its name, followed by some options, followed

by a pair of curly braces. Here is the first pass at our
complex number class.
class Complex
{
// functions and data members
}
In Visual Studio, you can build a class any time you like by
right mouse clicking on the

name of your project in the Solution Explorer (the project name will be in boldface). Then

from the pop-up menu, select
Add New Item...
. This will bring up a dialog box of


Visual Studio Installed Templates
”. Select the one called
Class
and give it a good

name, right then and there.
The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
6
Visual Studio will then create a new code module (i. e. a new file ending in .cs which has the

same name as the name you just gave your new class). Notice the pattern here: a tendency

to put each class in its own code module (its own file). This is an architectural model lifted

straight from Java. If you are creating this class as part of building an ASP.NET web

application you will get a message from
Visual Studio asking if you would rather place the

new code module in a sub-folder called
App_Code
. Generally you want to say Yes to this.
Everything else about the class is placed within a pair of curly braces, as shown.
C#
does

not use header files, so everything about the class will appear here.
Note that there is no

semicolon after the name and the opening curly brace. Go straight to the curly braces and

into the code.
Normally the class itself will be inside a
namespace
construct for sensible naming, but

that is a discussion for later.
By default, your class inherits from
System.Object
. We will see more of this later on

as well.
Now let's add some data elements to this class. Recall that a complex number has both a

real part and an imaginary part. So far, so good, but the next question is, what sort of

number should be stored for each? We could declare these as
integer
, but that would be

overly restrictive, so perhaps a single- or double-precision number would be more

appropriate. For maximal generality, using
double-precision probably makes more sense

than single-precision. Our class now looks like this.
class Complex
{
public double real;
public double imag;
}
At this point, the class is actually now usable, although it doesn't do too much. Note that

both the
real and imaginary parts are declared
public
. This is probably OK to do here,

since if a number can be given a legal double-precision value for an ordinary real number, it

is just as legal to do so in a complex number. Later we will see cases where declaring the

data member
public

is probably a bad idea.
Constructors
So far we have been talking about designing classes. How do we actually use them in real

The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
7
code?
Creating an instance of a class (that is, an object) is done with special methods called

constructors
. A constructor is what the user of the class calls to bring an instance of the

class into being. Using our complex number example, we can create two instances of

Complex
like so:
public Complex R1 = new Complex();
public Complex R2 = new Complex();
When this code is executed, two new complex number objects, R1 and R2 come into being.

Note, however, that although these two objects come into existence, their real and

imaginary parts remain undefined. Why is this? It's because we didn't explicitly design our

class to deal with this situation, and leaving matters to defaults isn't always good practice.

If we don't write a constructor for our class, a default constructor (one that takes no

parameters) is assumed.
So let's do some more work on the
Complex
class.
First thing, is to add a constructor, one that takes no parameters, that simply sets the real

and imaginary parts to zero.

class Complex

{

public double real;

public double imag;

public Complex ()
{
real = 0.0;
imag = 0.0;
}

}
Notice how the constructor is written. Its name must be the same name as the class itself...

this is how the compiler knows that you mean to write a constructor. It is followed by an

empty pair of parentheses, signaling that it is a method of some sort. Inside it (as defined

by the curly braces), we have code that explicitly sets the real and imaginary parts to zero.

Now we can get clean behavior from instances of our Complex class.
Multiple Constructors and Signatures
The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
8
We will see later that C# lets us write multiple constructors for classes we design. Most

modern OO languages support this. This is called
overloading
., and it is very useful thing

to be able to do in object-oriented programming.
You will often want to define multiple constructors for the classes that you develop. But

each constructor must have its own unique “signature”. A
signature
refers to the unique

and particular arrangement of parameters that is passed to a method. (This is actually the

case for any method, not just constructors.) For example, these two methods have the

same name, but different signatures:
public void WriteLine (int value);
public void WriteLine (string value);
No two constructors (or any set of same-named methods, for that matter) for the

same class can ever have the same signature.
It's the structure of the signature, and the

fact that they all differ, that allows the compiler to know which version of the method to

apply when multiple versions are available. Inside the FCL, there are many, many places

where multiple versions of a method are available. For example, the
ToString()

method for the
DateTime
class offers several variants to provide formatting options of

how the date/time string is to appear.
Continuing our example, we can add two more constructors in the hope that we can make

our class more useful. We will add two more: one which takes one double-precision

argument, and one that takes two
double-precision arguments, like so::

class Complex

{

public double real;

public double imag;

public Complex ()
{
real = 0.0;
imag = 0.0;
}

public Complex (double re)
{
real = re;
imag = 0.0;
}
The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
9

public Complex (
double re, double im
)
{
real = re;
imag = im;
}
}
It should be clear what is going on. The one-argument version allows the user to specify

the real part when constructing a new
Complex
object. The two
-argument version allows

the user to specify both parts when constructing a new
Complex
object.
public Complex R1 = new Complex(12.3);
public Complex R2 = new Complex(12.3, 4.56);
This all works just fine, and gives the user some latitude when using the class.
Destructors
Many OO languages also support the idea of the Destructor, a method that cleanly destroys

an object, that is, frees all its memory.
You usually do not need to write destructor methods

for your classes in the .NET framework. Since .NET garbage collects no-longer-used

objects for you, however, there is usually no need for explicit destructor methods in the

.NET framework. C# doesn't even have a special syntax for it.
However,
C#
does have a mechanism for speeding up destruction of unneeded objects, in

those cases where you need to speed up their destruction. If so, your class should

implement the

IDisposable
interface, which is discussed in greater detail later in this

article. This is generally needed
only when your class makes use of “precious system

resources” that have to be returned well before the Garbage Collector gets around to it.
Overloading Methods
An overload is done to the
same-named
method when you want to provide several

variations of the method all under the same name.
Each version of a method must have its

own unique signature. We already saw how to do this for Constructors, but it can be done

with any method that it makes sense for. Hence, any method can potentially be

overloaded.
Remember, the signature is the
unique
and
particular
arrangements of parameters passed to

The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
10
the method, and so each overloaded method you write must have a different signature from

all the others. An example will help make this clear. Assume we have…
n
a class called
Employees
, which is a…
n
collection
of instances of another class called
Employee
.
We want to be able to look up an employee’s start date
by
either their
EmployeeID
or

their
SSN
:
DateTime started;
started = theEmployees.GetStartDate (1234);
started = theEmployees.GetStartDate ("123-45-6789");
In the above example, it is OK to have two methods for
Employees
both having the

name
GetStartDate
, since one version expects an integer and the other expects a

string.
The compiler can always tell them apart.
Visibility of Class Members
As noted earlier, you have very fine-grained control over how the members in your class

(both data and methods) are made visible to users of the class (object instances).
We look

at this in more detail now.
Visibility is something we can control for both data members (the “data”) and the functions

(the “methods”), so much of this discussion applies to either.
Easiest is simply to declare the member public, as it is both for the class itself

(
Employee
) and its data member
EmployeeID
.
public class Employee
{
public int EmployeeID;
}
A data member declared this way is sometimes called a field. It can both be read and set

without limitation (except that enforced by the underlying type) by users.
In general, simply

declaring a data member
public

is often unwise, since you then have no control over

what values users put into it.
C# offers the following
five levels of visibility, from most to least visible,
to control access

The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
11
to both data and methods:

public

internal

protected

protected internal

private
These five levels have the following meanings:

public

members are visible from any place else in the program, even from other

code modules (assemblies) that create instances of the class.

internal
members are only visible from inside the same code module. But

within that same code module, one object class declared there can access internal

members of other classes declared there.

protected
members are visible only from within the class to which it belongs or

from within any descendant of the class.
The descendant class code can be in

another module (and in fact probably will be). You will use protected-level a lot

when you design carefully thought-out class hierarchies.

protected internal
members can be accessed from within the current

assembly
or
from within classes that descend from the current class. It is b
asically a

union of the
protected

and
internal
modifiers.

private
members are visible only from within the class itself. That’s it; no other

class in any other module can access
private

members, not even
classes that

descend from this class.
Read and Write Access
In addition to controlling overall visibility, y
ou can additionally make data members read-
only, write-only (very rare), or both. You can also use this capability to perform validity

checks or take other actions when users attempt to write a value into a member for which

you supply write access. Data members set up this way are called
properties
. We then

supply “gets” and “sets” to access their values.

Write a
get
method to allow a user to read a member value.

Write a
set
method to allow a user to set a member value.

In your
set
method, you have an opportunity
to perform appropriate validity checking

before actually changing the data member's value. Refuse to follow through on setting a

value if you are handed bogus data.
The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
12
To create a read-only property, omit the
set
method.
There will then be no way for users

of your class to change that data value. To create a write-only property, omit the
get

method.
Write-only is generally poor practice, since the behavior that results can be confusing for

users of the class. About the only legitimate use for write-only is for setting secret

encryption keys. Once the class itself (more on this later) sets the secret key no one using

the class can see what it was. If you must have a write-only property, it is usually better to

write a completely separate method (one that is not part of the get/set pair) to deal with

these write-only cases. This minimizes confusion among users of your class, who would

otherwise see the write-only property as something of a mysterious “black hole”.
You often want to write your
get
or
set

methods to perform other actions that make

sense inside your class (like ensuring internal consistency or causing an intentional side

effect).
get
usually simply returns the property value, but you could, for instance, also log

the access somewhere.
set
is best used for performing appropriate tests on the passed-in

new value before changing the value. You may also want to have certain side effects take

place inside the object whenever a value is changed using
set
. Writing a log entry to a log

file might be one of those side effects.
What does this look like in C#? Say that somewhere inside of a class is a declaration for a

variable named
itemQuantity

whose access we want to tightly control. The code could

look something like this:
private string itemQuantity;
// lower case
public string ItemQuantity
// upper case
{
get
{
return itemQuantity;
// returns the private value
}
set
{
// value is built-in and always
of correct type
// only change itemQuantity if the test returns True
if ValidateItemQuantity (value)
{
itemQuantity = value;
}
}
}
The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
13

Here we allow ready retrieval of
itemQuantity
, but allow its value to be changed only

if it passes muster in a call to

ValidateI
temQuantity()
. Only if its value is OK do

we actually commit the change.
Note the .NET naming conventions found in the above example.
The data member itself

is declared
private
within the class and its name begins with a lower case letter. The

corresponding property is declared
public
and its name is the same as the private data

member, except that it begins with the upper case letter.
This is considered standard practice (since
C#
is case-sensitive) and makes for very clear

code. A
lso note that:

get
and
set
appear as shown, in lower case, and
without
parentheses.

The
get
and
set
appear immediately after where the property is defined.

Unlike the
C
++ convention, you do
not
supply a passed-in parameter for the new

value in the
set
method.

The compiler implicitly assumes exactly one passed-in parameter for the
set

method, whose name is always
value
, which is automatically and always the

same type as the underlying property.
An unfortunate design decision in
C#
is that you end up with the same access permission

for both
get
and
set
, since

only the data member itself that has the access modifier

attached. In other words, you cannot declare the
get

to be public and declare the
set

is

to be
protected
, for example. Yet you may in some cases want to restrict the ability to

set a value to derived classes only (i. e.
protected
), while allowing
public
read access.

The only way to do this is with a workaround: Write a completely separate method (marked

protected
, or whatever), and perform the value-setting code in there, and omit the

usual
set

method. Then, only derived classes will be able to do set calls to the property.
Finally, note that C# handles this sort of thing differently from C++.
The older

convention from C++ looks like this. For a member named
MyField
, write:
private int MyField;
public fieldtype GetMyField();
public void SetMyField (value fieldtype);
(The actual code isn't shown.) Here,
GetMyField()

need only return the value of

MyField
, but
SetMyField()
can and should ensure that the value passed in makes

sense before actually changing the value of
MyField
.
The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
14
Static Members
Static members are ones that
exist only at the level of the class. These are declared with the

keyword
static
.
In the case of data members, only one such “instance” exists, and it belongs to the class

itself. Static data belongs to the class, not to any one object. No matter how many or few

instances of the class are created, only the one static instance exists, and its value is

(potentially) available to all object instances (provided that it was also not declared

private
).
Many times, when you do permit access to the value of a static data member, you want to

grant only read-access and strictly control write-access, which is why you are probably using

static

in the first place. In such cases, you might provide for a separate method that

controls writing to the static data member, and that method may be declared
protected

or given some other restricted status, or it may impose other restrictions on its use.
static

has uses in constructing things like the design pattern called the
Singleton
, the

correct way to implement “global” variables in those situations where you really think you

need them.
Static data members are also often used inside of the class constructors and a

few other places you control.
In the case of static methods, the method, too, belongs to the class and not to any

particular instance of the class. Recall that the method called
Main()
, which is where

execution begins in a C# program, had to be declared
public void static
or

public int static
, since execution had to begin somewhere, before any instances

of any classes are brought into existence.
In the example given earlier, for the write-only encryption key, you would probably want a

static

method in the class itself that took care of setting the secret
encryption
key. By

also declaring it
private
, you could ensure that no other caller could ever access this

critical piece of code, and that, once set, it could not be hacked or changed. (Of course,

there are often ways for a clever hacker to get around this, but this isn't a course about

computer security, which is a vast topic in its own right.)
Exploring the Framework Class Library (FCL)
The .NET Framework Class Library is the
foundation of all .NET programming. The FCL

contains thousands of useful classes. The underlying framework of the FCL also permits

The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
15
third-party vendors to develop additional class libraries for particular problem domains. As

developer, you also get to extend the FCL with classes of your own design.
All .NET- aware languages, and
C#
in particular, are necessarily deeply intertwined with the

FCL.
As we have seen, the syntax of
C#
itself is not much different from other languages

which which you may already be familiar. Proficiency with .NET is largely a matter of

knowing something about the full range of the classes available to you. In practice,

however, you really only need to know about a couple of hundred classes to be able to do

useful work in .NET. Most of the other classes are highly specialized and are needed very

rarely, if at all.
All Objects in .NET descend from
System.Object
, which is the master class for all

Objects both in the Framework Class Library and for any classes you develop.

System.Object
defines a number of core methods that are useful everywhere

throughout .NET and in all children classes.
In
C#
code, you can use the keyword
object
(lower case) as a shorthand for

System.Object
.
We will look more closely at the inner working of

System.Object
during class time.
A Few Handy Classes
Remember that everything in .NET, except for the fundamental types like integers and

floating point values, are objects.
In particular, everything we use to create visual elements, whether in Windows applications

or Web
applications
, are built up from a wide variety of objects. Much of the FCL consists

of a powerful set of visual objects, an entire set for building standalone Window

applications and another set for building Web applications.
Visual objects
are objects that know how to draw themselves and respond to events. They

are a big part of building graphical user interfaces (GUIs). Getting comfortable with the

large set of visual objects is part of the essential skills in building these sorts of

applications.
In the early labs, there were a number of classes that did most of the hard work.
n
DateTime

– knows all about managing dates and times
n
TimeSpan
– knows how to deal with
intervals
of time
n
Convert
– a smart way to convert data types
The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
16
n
Math
– where
Sin()
and

(
Math.PI
) live
n
Session

– essential for keeping track of web clients
n
Response
– used to jump from one web page to another
The
Console
Class
The
Console
class is provided in .NET for building simple console applications (which

run in MS-DOS style terminal windows). Console applications are surprisingly useful for:

Building and testing simple classes of your own,

Building b
road classes of utility programs, essentially for doing the same sorts of

things as PERL does.
The main methods we are interested in for the
Console
class are:

Read()

ReadLine()

Write()

WriteLine()
The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
17
Inheritance - The Second Pillar
As we have seen, the Three Pillars of Object Oriented Programming are:

Encapsulation

Inheritance

Polymorphism
In this section we look at Inheritance.
Inheritance is the Second Pillar of OOP. E
ssentially, i
nheritance
is the ability of the object-
oriented framework in a language to let you design new class definitions based on existing

class definitions.
Inheritance is closely related to polymorphism, the Third Pillar of OOP.
The term
parent
or
ancestor
class refers to the class from which we derive.
The term

child
or
descendant
class refers to the new class we are designing from the parent.
Broadly speaking, inheritance comes in two flavors:

Single Inheritance
– the child class can derive from only one parent class.

Multiple Inheritance
– the child class can derive from several parent classes.
Many OO experts now regard multiple inheritance as a bad idea, although experts do not

agree on this point and some think
multiple inheritance is just peachy. For those who do

not like multiple inheritance, however, there is a related capability called the Interface

which can provide many of the same capabilities. Note that this use of the word

“interface” has quite a different meaning than it does in, say, User Interface.
Multiple Inheritance
As OO evolved, it became evident – at least to some experts – that multiple inheritance was

a mistake, and so n
ewer and better ways to handle the alleged need to have multiple parent

classes were devised:

Ordinary “has-a” relationships

Containment-Delegation

Interfaces
Pure inheritance itself reflects the “is-a” relationship.
Is-A and Has-A
The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
18
Conceptually, these two epistemological ideas go to the heart of Inheritance.

A
car

is-a

vehicle

A
car

has-a


radio
It is perfectly OK for one class to contain references to other classes, or even references to

the same class… this is u
seful for things like trees and linked-list objects.
Containment-Delegation
In a Containment-Delegation relationship, one class “has-a” another class.
The latter class

(which we can call the “inner” class) is
contained
by the owning class (the “outer” class). In

the above example, the car has-a radio.
The outer class can then make as much or as little of the functionality of the inner class

available as it likes, by supplying methods of its own that simply call methods of the inner

class (this is
delegation
).
This allows users of the outer class to get at carefully-selected functionality of the inner

class, as exposed by the outer class.
Consider the
car
has-a
radio
scenario:

The
car
class can offer to outside callers services like
TurnRadioOn()
,

TurnRadioOff()
,
SetRadioVolume()
, etc.

These methods in turn call methods that belong to the actual
radio
object.

The caller of the “outer” methods is unaware that delegation has taken place inside

them. It's none of the caller's business.

The inner workings of
radio
are kept hidden from the user of the methods

offered by the outer class.
The Interface
This is the third way of avoiding multiple inheritance. We will return to it after we see how

multiple inheritance works in C#.

How Inheritance Is Done in C#
If your class inherits from another, follow the class name with a colon, followed by the

class it inherits from:
The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
19
class MyNewClass : OrgBaseClass
{
// same as before
}
Recall that .NET is based on the single inheritance model, so only one ancestor class (the

one after the colon) can be specified.
When you create a class that inherits from another class (its parent or ancestor), everything

from the parent or ancestor class is inherited. This is a powerful way to extend the

capabilities of existing classes by letting you customize and extend their behaviors in ways

more appropriate for the problems you want to solve.
Adding Interfaces
Since .NET
is based on the single inheritance model, you can have only one ancestor

class, b
ut you can add as many Interface definitions as you require. These are

simply listed after the base class, separated by commas. Here's an example:
class MyNewClass : OrgBaseClass,
IDisposable, ICloneable
{
// same as before
}
In this example,
MyNewClass
descends from
OrgBaseClass
, and also agrees to

support the
IDisposable

and

ICloneable

interfaces.
More about Interfaces
We have mentioned the Interface as a way of avoiding multiple inheritance without exactly

explaining what an Interface is.
In essence, an Interface represents a different form of a has-a relationship, but not in the

same sense as object A “has-a” reference to object B. Rather is is more like saying that an

object A “has-a” particular capability. For example, you may want a class to be able to

print out its values to a printer. In that case, you
may
want to have an interface called

IPrintable
, which provides for this
capability for
printing.
An Interface is then essentially a
contract
, an agreement to support whatever actions the

Interface defines.
When you add an Interface to your class definition, you are essentially

The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
20
promising that you will supply working code for every method defined in that Interface. If

you don’t, users of your class who expect the promised functionality will see things break.

This is not good.
The purpose of this contract is to permit users of the class to be able to rely on a stable,

clear and consistent definition. This is how it is possible for a user of an object class to

know in advance that, if an Interface is supported by a class, the class can be relied upon to

do the right thing. With Interfaces, even classes that are quite dissimilar may still implement

the same Interface for some reason. You access the methods of the Interface in one class

the same as you would the methods of the Interface the other class, and can even put in

cast operators to make that happen. With class hierarchies this would usually be a mistake,

but it makes sense for Interfaces.
Note that Interfaces are
not
classes, only a kind of chunk of code that can be made part of

classes.
By convention, the name of any Interface starts with capital-I.
An Interface is a template that defines some number of methods that make up the

interface, i. e. the names and signatures of those methods. The Interface definition itself

does not, and
cannot,
contain any code.
You
must supply the code for the Interface if you

choose to support the Interface in any of your class definitions. That’s part of your

contractual obligations you took on by including the Interface.
.NET defines a number of useful Interfaces that you can use in your own code. One of

these is called
IDisposable
, and it is used for those situations where you want to take

control of when garbage collection occurs for instances of your class that are no longer

needed.
IDisposable

defines exactly one method called
Dispose()
, which, when

called,

destroys whatever data your class defines, as well as perform any other clean-up

actions that your class might require. If you include it in your class declaration (as in the

above example) then you must write code for its corresponding method
Dispose()
.

IDisposable

is a simple Interface; others may require rather more work from you.
The act of supporting an Interface is called
implementing the interface
. In summary, i
f you

implement an Interface, you must then ...

supply all the necessary code...

using the exact names and signatures as defined in the Interface itself…

but some of these can be stubs (i. e. contain no code), if that makes sense within the

context of how you are using the Interface.
Restrictions On The
Interface

The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
21
Interfaces
cannot
contain any code. This means they cannot include
get
s
or
set
s,
either.
Interfaces
do contain
declarations
of methods, properties, indexers, and events, but not fields.

The rea
son Interfaces cannot contain fields – it would imply a declaration of some variable

within the Interface, yet you cannot have any code there.
You do not ever instantiate an Interface they way you would a class. In other words, you

cannot bring an instance of just an Interface into being.
Instead you include the name of

the Interface in your class definition and then fill in all the code that the Interface requires

you to supply when you write the code for the class.
In
C#
, you indicate the Interfaces you intend to support by listing them in your class

definition following the colon and the ancestor class (if any).
If you support multiple

Interfaces, list them, separated with commas (see the example for
MyNewClass

above).
Note that a derivation from an Interfaces acts completely independently from a derivation

from a base class.
For e
xample:
class MyNewClass : IDisposable
or

c
lass MyNewClass : BaseClass,
IDisposable
or



class MyNewClass : BaseClass, IDisposable,
ICloneable
An Interface cannot define any constructors, because it is not a class.
Instead, the code for

the Interface methods that you write simply becomes available to instances of your object.

Recall that you contracted to support the Interface.
No operator overloads are permitted, so that languages that don't support operator

overloading can still support Interfaces.
Inside the Interface definition itself, a
ll Interface members must be
public
.
They have to

be, otherwise there would be no way to expose them to view.
There cannot be any
virtual
methods inside an Interface, since no polymorphism is

possible with an Interface. There d
efinitely cannot be any
static
methods, since there is

no code allowed in the Interface definition, and if a method were
static
, you would

have to supply code. If you really need
virtual
or
static
methods, provide for them

in the
implementation
of the Interface; tt just cannot be imposed by the Interface definition

The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
22
beforehand.
Inside your class, you must write code for all the methods called for in the Interface(s) you

chose to support. T
hese methods must be written with the exact signatures previously

defined for them by the Interface. You will get compilation errors if you leave any

methods out, but it is OK to write a method that "does nothing" (called a stub) if that is

the most sensible thing for your class to do with this Interface.
The
IDisposable

Interface
A sometimes useful interface in .NET is
IDisposable
, mentioned earlier.
It defines a

single method,
Dispose()
.
public interface IDisposable
{

void Dispose();
}
You will usually want to support this Interface for a class that you develop if that class is

making use of some resource whose lifetime must be controlled. These are often “legacy”

components like
COM, Active-X, etc., which predate the .NET framework, do not

participate in .NET garbage collection, and which require explicit memory management on

the part of the programmer.
Other places where this may be appropriate are for external resources, for example a log file

that the class has to write to. You want to be sure to close any file handles before letting

your class be garbage collected. Also, things like network socket connections or other

operating system resources. O/S resources should always be considered “scarce”, and you

generally want to free them as quickly as possible when you are through using them.
Declaring Your Own Interface
You can create your own Interfaces for use in other classes that you want to write. A
ssume

for example that you want to create an Interface called
IBankAccount
to represent

money for a department in an ordinary business. You want it to represent a money

amount, as well as the notions of depositing and withdrawing money (that is, define

methods for depositing and withdrawing money).
You could then use this Interface to represent movement of money between departments

(similar), or between a department and the bank holding the account (dissimilar).
You

The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
23
would of course then need to deal with the fact that a deposit to one is a withdrawal from

another. The beginnings of a declaration for this Interface then could look like this, in C#.

(Of course, a real system would probably have more complexity in here than this.)
namespace MyCompany.MyBigApp.MainProject
{

public interface IBankAccount

{

void Deposit(decimal amount);

bool Withdraw(decimal amount);

decimal Balance

{

get;

}

}
}
A Canonical Inheritance Tree
Let's get back to that Second Pillar, Inheritance. We have just seen some ways, notably

Interfaces, which let us avoid things like multiple inheritance, but now lets look at what

inheritance is all about. Say we want to build some sort of “paint” program, and as part of

doing this, we want to let users draw various shapes on the screen. This suggests an

opportunity to construct an inheritance tree to represent these shapes.
The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
24
Here,
Shape
is going to be a parent class for all the specific shapes we want our paint

program to support. Why do we want to do this? Well, it is likely (in fact, probably

inevitable) that all shapes will share some common items of data, like height, width,

position and color. These are best “factored out” into the
Shape
class, from which each

particular shape sub-class will inherit. But how best to handle the
Shape

class?
Abstract Classes
An abstract class (declared with the keyword
abstract
) is a class in which it is
illegal
to

create instances of the class.
Why would we do this? In the above example, the
Shape

object is something we would not want allow anyone to create directly (it has no actual

“shape”!).
Instead, we want users to create specific shapes by using the many specialty

shape sub-classes that we supply.
Nevertheless, in the
Shape
class, we will define a number of members – both data and

methods – common to all shapes that derive from this class. Some of these could easily be

height
,
width
,
top
,
left
, and
color
. These are all data elements that probably

make sense to include in a
Shape

object, as well as an abstract or virtual method for

actually drawing the shape,
Draw()
.
Because the parent class is abstract, all child classes
must
supply actual working code for all

the methods. After all, h
exagons are drawn differently from ellipses.
The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
25
Object
Shape
Ellipse
Triangle
Rectangle
Hexagon
We would probably
define this as an
abstract class
Polymorphism
Object
Shape
Ellipse
Triangle
Rectangle
Hexagon
We would probably
define this as an
abstract class
Polymorphism
Note, however, that there likely going to be some common set-up code that we want in

Shape.Draw()
, which is the method found in the (abstract) parent class. This could be

set up code, for example, for preparing a “drawing context” that gets things ready to

actually draw the object. If that is the case, then it would certainly be convenient to do this

set up in a centralized location, and that location is most sensibly
Shape.Draw()
.
If so, then we want to declare the

Shape.Draw()

method
virtual
, not
abstract
.

This means that this method will in fact contain callable code, which is exactly what we

want. Note that the
Shape

class itself can still be declared
abstract
, with a method

declared
virtual
, and that is perfectly all right.
Why Do Abstract Classes?
We make use of abstract classes mostly to produce better designs!
Think of it as an

opportunity to “draw a line” in your design and define a class for which you intend to

derive many useful subclasses.
You “factor out” as many common data members as you can and put them in the abstract

class.
You also “factor out” as much useful functionality as you can and put it in as method

definitions in the abstract class. This was the whole point of having an abstract class in the

above example, from which as many different shapes (sub-classes) as we desired could be

derived.
As we saw, not every member in an abstract class needs to be abstract.
But if
even one
is,

the whole class must be regarded as abstract, and instances of the class
cannot
be created.

This makes sense, because with even only one member declared as abstract, there would

then be no way to create an instance of it.
How C# Does It
In .NET, everything somehow inherits from a built-in class, unless it is a simple value type,

like integer or Boolean.
By default, every class inherits – at the very least – from

System.Object
, unless it inherits from something more appropriate. As we have seen,

namespaces are used to help keep it all organized.
Recall that .NET is based on the single inheritance model, so only one ancestor class can be

specified.
So only simple Inheritance from another class is possible. This is how we specify

the inheritance.
The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
26
As we have seen, though, you can include as many Interface definitions as you require.

These are simply listed after the base class, separated by commas.
Once you have created a class which inherits from some parent class, what happens next?
Time to add whatever data members and methods you need to get the unique new

functionality you want your class to have.
As always, you have very fine grained control

over how this is done.
The first concern is whether our class needs to be made
abstract
or not.
This will

usually be useful when you intend to create two or more different subclasses, an idea we will

return to in the Third Pillar: Polymorphism. If you make your class
abstract

(or if

even one data member or method is declared
abstract
), then you will of course need to

supply some subclasses, or else require users of your class to create their own subclasses.

Remember, no instances of an abstract class can ever be created.
The
abstract
Keyword
Having a property declared
abstract
declares the type of the property (and whether it

has
get
or
set
or both) but supplies
no actual code
for getting or setting.
Derived classes

must supply the
get
and
set
code.

A method declared
abstract
in the parent class definition implies that its child classes

must
implement the same-named method, since there is no code whatsoever in the abstract

class itself.
The
virtual
Keyword
A method declared
virtual
in the parent class definition indicates that it can be

overridden in child classes.
The child class can then
override
the method, using its own

code, with the
override
keyword. Overriding in the child class is always optional, since

the base code is still available.
Virtual members include both properties and methods (but usually not fields).
You don’t

have to override the code of a virtual method, but in most cases you will want to. If you

don’t supply an override method in the child class for a virtual method, the system simply

uses the code in the parent class. Sometimes this is exactly what you want.
If you don’t include the
override
keyword for a method in your derived class, you are

effectively hiding the method in the parent class.
This is usually a mistake.

If you do

want to hide the parent method, the keyword
new
should be used in the method

The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
27
declaration to indicate you want this behavior; otherwise you get a compiler warning from

Visual Studio.
When you do override a virtual method in the ordinary way, you may often still want to call

the original code in the parent class (because, for example, it does something useful

common to all subclasses). This could be the case in our
Shape
example, where a method

called
Shape.Draw()

does some useful set-ups, perhaps like retrieving a “drawing

context” for the graphics system you happen to be using, and you need to do this for

whatever hexagon, ellipse, etc. the user happens to be drawing.
To do this, add the
base
keyword as shown when you need to call the original parent

method:
base.
<MethodName>
In the
Shape
example in, say, the
Hexagon
's
Draw()
method, you could call the

Shape
's
Draw()
method:
class Hexagon : Shape
{
...
public void Draw ()
{
base.Draw ();
// Calling Shape's Draw method
// Draw the actual hexagon...
}
...
}
Overloading and Overriding Methods
Don’t confuse
override
with overloading
.
override
means you intend to supply a

method in a descendant class that is to be called instead of the same-named method from

the parent class that it descends from.

O
verloading

means to declare multiple versions of a

method with the same name but with different arrangements of parameters (i. e. having

different signatures). For overloading, all versions of the method are named identically;

only their signatures are different. The C# compiler is smart enough to detect when you

are overloading a method. However, some languages do supply an
overload
keyword to

signal the desire to set up overloaded methods.
The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
28
The
sealed
Keyword
Use the
sealed
keyword on a method to prevent it from being overridden by any

descendant class.
When used with a method, that method overrides an inherited virtual

method, but no classes that inherit from this class can override it any further.
sealed

must be used in conjunction with
override
.
sealed

can be applied to an entire class, in which case users of the class must create

instances of that class itself; they are not going to be able to create subclasses from it.

String
is a notable instance of a sealed class.
A Warning and a COM Sidebar
Microsoft has an older technology called the COM object that has been a mainstay in

Windows programming for years. COM objects are the basis for so-called VBX and OBX

visual objects, the very large set of Active-X objects, and extended objects called COM+

and DCOM objects.
All these
COM objects (now considered legacy) define an elaborate Interface mechanism

that has
nothing to do
with the Interface mechanism for .NET that we have been

discussing here. The .NET Interface mechanism is
entirely unrelated
to the COM version,

but is modeled instead after Java.
In fact, if you want to use COM objects in what is otherwise a .NET application, you have

to manage their usage. Since they are not .NET classes, the Garbage Collector cannot work

with them. If you have occasion to work with COM objects of any sort, be careful not to

get confused by its use of Interface versus the meaning it has in .NET
The interface mechanism for COM objects begins with the
IUnknown
interface.

IUnknown
is the simplest COM interface, and all COM objects must support it. It is a

way for a caller to ask the COM object what it knows how to do and what other, more

detailed, interfaces it supports.
From there a caller of a COM object can find out what other interfaces that COM objects

supports, and if that matches the caller's expectations, the caller can now work with the

COM object via the interface it knows how to use.
This mechanism was actually quite new and useful for its day (plus, it “worked”) but it had a

few nasty properties that could trip up the unwary programmer. For one thing, it had a

The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
29
primitive notion of garbage collection of its own: every time a programmer wanted to use a

COM object the programmer had to
arrange for the program to
“register” its usage; then,

when the program was finished with the COM object,
the programmer had to arrange for

the program to
“unregister” it. If all went well, these would be in balance, and the run-time

code that managed COM objects would be able to get rid of ones that were no longer in

use. However, it required that programmers really register and unregister COM component

cleanly; if a program ever “forgot” to unregister a component that it had registered, or,

worse, if the program crashed before it could
unregister the component, then
the

component would never be released from system memory and this would eventually impair

the operation of, or even crash, the operating system itself. This was one cause for Blue

Screens of Death (BSODs).
To note again: This is
not
the mechanism found in .NET for component management or

garbage collection.
More About Constructors
In .NET there exists the
Object()
constructor, which is ultimately the boss constructor

for every object that gets built in .NET.
As we have already seen, the
constructor
is how we

create new objects at run-time. You may sometimes see this abbreviated to “ctor” in some

discussions about .NET or other discussions about object-oriented programming.
Eventually any constructor for any descendant class, either built-on ones or ones you

design, calls this method to set up the basic info common to all objects. One reason this

has to happen is to let the .NET run-time know about all the objects that are getting

created so that garbage collection can operate correctly with them. Recall that objects in

.NET are created on the managed heap. The
System.Object
class knows all about

how to work within this environment, and so your classes do as well.
There is more going on with constructors than meets the eye.
There are actually three

types of constructors:
instance
,
private
, and
static
. The one we're most familiar with is the

instance constructor – it's the kind that is invoked when you use the
new
keyword.
As we have seen, if you don’t supply a constructor for a class you design, a default one is

provided. D
efault constructors take no parameters.
But most constructors can be overloaded, and, in many cases, they should be. Providing an

appropriate set of constructors is an important part of designing a class well.
Constructors can also “chain”, which means that one constructor can call another

constructor, which can call another constructor, and so on. Sometimes a constructor calls

The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
30
another constructor from within the same class; other time a constructor can call a

constructor from a parent class. More on all this below.

Instance Constructors
These are the kinds to use when creating
objects
, which are instances of
classes
. As noted

above, this is the kind of
constructor invoked when you use the
new
keyword.
The layout for this kind of constructor is:
[
attributes
] [
modifiers
]
identifier
([
formal-parameter-list
])
[
initializer
] {
constructor-body
}
[
attributes
]
are used occasionally make use of various kinds of preprocessing

directives (we haven’t talked about this in class yet).
For more about attributes, see

Conditional
directive
and
Obsolete Directive
in dynamic help.
[
modifiers
]

are, optionally, the keyword
extern
and one of the four standard

modifiers:

public

protected

internal

private
extern
is used to import methods from other modules or DLLs. See dynamic help for

details.
i
dentifier

is the name of the constructor, which of course is identical with the name

of the class itself.
This is followed by
formal-parameter-list
,
the list of

parameters the routine takes. The particular pattern of the parameter types constitutes, of

course, its
signature
. You can have multiple constructors (or indeed multiples of any

method) as long as each one has its own unique signature.
Here is an example of a simple class (with inheritance) that has two constructors, both

declared
public
.
public class MyChildClass : MyParentClass
{
public MyChildClass()
{
// constructor code goes here: do stuff
The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
31
}

public MyChildClass(int ID, string name)
{
// do more stuff
}
}
The
initializer
is patterned after
C
++ and is a great feature of
C#
. It tells the

compiler that, just before calling this constructor, it must call the

initializer

constructor first.
Initializers can be either
base
or
this
, followed by a list of arguments:

base

(arg-list)
means to call the constructor having that arg-list signature in

the
parent
class.

this

(arg-list)
means to call the some other constructor having that arg-list

signature in
this
class.
Note that, since many of your classes will descend from existing classes, you will often want

to first do all the standard set ups the parent class constructor provides. The
base

initializer lets you do this easily.
If constructors in one class can reliably call the
base

initializer of its parent class, and so on, then initializing can “chain” all the way up to

System.Object
.
Similarly, if one of your constructors does a lot of work doing set ups, then other

overloaded constructors in your class can invoke this heavy-duty constructor by calling it

with the
this
initializer. If that heavy-duty constructor itself uses the
base
initializer,

then a lot of work can be done easily and correctly, with all the set-ups begin done in the

places where they belong. Learning how to design these sorts of constructors and

constructor chains is an important part of doing quality OOP.
Here is an example:
public class MyChildClass : MyParentClass
{
// This constructor calls the parent's constructor
public MyChildClass() :
base ()
{
// constructor code goes here: do stuff
}

// This constructor calls this class's constructor ,
The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
32
// the one just above.
public MyChildClass(int ID, string name) :
this ()
{
// do more stuff
theID = ID;
theName = name; // etc.
}
}
A Caution About Constructors
No matter how you set up the constructors, one point is key:
Never put code that could

potentially fail into a constructor.
Example: code that depends on being able to acquire

a system resource… the resource might not be available at that moment.
Instead, supply another method (often called
Initialize
) to handle this. You can set

this up so that it
can return a Boolean for success or failure. Then use that fact when doing

initialization to signal abnormal situations.
Weird Constructors
The last two constructors we are going to look at are a little odd, but definitely have their

uses.
Private constructors
can be used for the Design Pattern called the
Singleton
, the correct

way to have “global variables” if you must have them.
Static constructors
can be useful for making objects database aware. The
Employees

class could use a static constructor to prepare itself so that it knows how to create “the next

new employee ID” by connecting to a database and finding the largest ID number of any

existing employee. More on this much later in the course.
Private Constructors
Any class containing a constructor marked
private
prohibits instances to be created.
Such
constructors c
annot be called directly (since they are
private
).
Why would we ever

want to have this?
Private constructors are often used with static classes, which, in effect, “already exist”

when referenced. Therefore they are good for managing things like global constants, math

libraries, incrementing counters, etc. While they do not come up every day, when you need

The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
33
this particular behavior, nothing else will quite do. See the .NET on-line help for more

info.
Static Constructors
Static constructors are a way to guarantee that certain things
in the class itself
get initialized

before any instances of the class are created.
Static constructors cannot be accessed. Static constructors cannot take arguments.
You

cannot control when it gets called, but you
can
rely on it getting called before any instances

of the class are created.
The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
34
Polymorphism –
The Third Pillar of OOP
Let's
return to the earlier
Shape
diagram, which
illustrates an example of polymorphism.
In our design, we can assume that e
ach shape has its own idea of what it is and how it is to

be drawn, yet they are all shapes. The
Shape
object is probably best made
abstract
,

although it doesn’t have to be. We would now like each of our polymorphic classes to

know how to draw itself.
In the above, the
Shape
class defines a method
Draw()
which is going to be declared

either
abstract
or
virtual
.
Each subclass will
override
the definition of this

method and provide the code that makes that particular class draw itself correctly. If the

parent class method is declared
abstract
, then of course the child class
must
provide an

implementation.
Virtual Members
Virtual members (both data and methods) are part of the third pillar of OOP,

polymorphism.
A method declared
abstract
in the parent class definition indicates that

it
must
have the same-named method supplied in child classes. A method declared

virtual
in the parent class definition indicates that it
may
be overridden in child classes,

because there is already some code in the virtual method that is probably useful for a

subclass to access. The child class can then override the method, using its own code, with

the

override
keyword, which is always optional but usually desirable. The set-up we

The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
35
Object
Shape
Ellipse
Triangle
Rectangle
Hexagon
An abstract
class
Polymorphism
Object
Shape
Ellipse
Triangle
Rectangle
Hexagon
An abstract
class
Polymorphism
have in our paint program looks something like this:
Virtual members can include both properties and methods (but not fields, except as a hack).

Static methods and properties cannot be declared virtual; it’s meaningless!
You are not required to override the code of a virtual method, although in most cases you

will want to.
If you don’t write an override method in the child class for a virtual method,

the system will simply use the code in the parent class.
If you don’t include the
override
keyword for a method in your derived class, you will

effectively hide the method in the parent class.
You will rarely want to do this. If you do,

the keyword
new
should be used in the method declaration to indicate you want this

behavior, otherwise you get a compiler warning.
When you do override a virtual method in the ordinary way, you may still want to call the

original code in the parent class (because for example it does something useful that is

common to all subclasses).
Use this construction to call the original method in the parent class:
base.<MethodName>
The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
36
Object
Shape
Ellipse
Triangle
Rectangle
Hexagon
public void Draw()
Draw()
Draw()
Draw()
Draw()
Object
Shape
Ellipse
Triangle
Rectangle
Hexagon
public void Draw()
Draw()
Draw()
Draw()
Draw()
Why Do All This?
The beauty of this has to do with working with large collections of similar – but not the

same – objects, for example, a draw program as we have here.
In that example, note that

the array contains elements declared as type
Shape
, not any particular shape, since we

don’t know what shapes our users will actually use.
Later on, each of the
Shape
objects (of whatever subtype they actually are) will get drawn

using that particular shape’s own
Draw()
method, without any additional code needed on

our part.
The correct overriding method is instead determined at runtime.
Going in the other direction is problematical, however.
The declaration in the array was

for the class at the topmost level (
Shape
) that made the most sense to use. No need to go

all the way up to
System.Object
. Then, we used objects from various child classes for

the actual objects in the array.
When working with an array,
foreach .. in
is handy for accessing the individual

elements. The code for drawing the entire picture now becomes very simple indeed:
Shapes[] shapes = new Shape [MAX_SHAPES];

// ... time passes, now draw the shapes
foreach (Shape nextShape in shapes)
{
nextShape.Draw();
}
On the other hand, had we needed to “cross” classes we would need to apply a cast from

one class to the other. If your design seems to need this sort of behavior, rethink your

work, since it may be that you are doing something seriously wrong.
Conclusions
Getting good at OOP is a matter of understanding what the three pillars are all about and

what implications they have on how your (and other’s) classes are designed and used.

Object-Oriented Programming doesn’t save you from writing bad code… all you will be

doing is writing bad object-oriented code.
A well-designed library of useful classes is enjoyable and powerful to use (a bad one is not,

The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
37
of course).
The .NET BCL and the Java class libraries are examples of such libraries.
Your skills in
Object-Oriented Programming
in large part consists of knowing what’s

available in these massive class libraries and putting them to good use.
The Three Pillars of OOP – Copyright © 2007 by Michael F.. Lynch PhD
38