Object-Oriented Programming: What's it all about
The Object Oriented trinity that all programmers are familiar with is:
Often, this trinity of concepts is invoked as if they explained object-oriented design, or the need for such a methodology. Encapsulation, inheritance and design, however, are elements of OO design; they do not explain OO design. I thought I would point that out because there seems to be some confusion surrounding this point. OO Analysis and Design is the process of modelling software solutions through visualizing a problem as a set of discete objects. The "why" of the problem, i.e., why do we model solutions to problems as if we were dealing with a set of objects rather than a set of procedures can be explained by examining the nature of the problems that we often deal with.
First, let's demystify object-oriented programming. And
during its early days, and to some extent, even today, the very
words "object-oriented" conjured ideas of some lab coat
wearing mad scientist, basked in the glow of a bank of monitors,
gleefully rubbing his hands while bringing life to some
alchemical software "object." The more
sober amongst us realized from the start that object-oriented software
design was really just another software design technique. In
engineering terminology, software design technique is now
described as a paradigm. That, in itself, can be confusing,
especially because modern engineers tend to be a fairly illiterate bunch.
If we use a term, then we must understand it. Otherwise, we are lost.
The word paradigm is Greek and translates as example or pattern. It could also be
described as being a perfect example or exemplar. Now, if we
perform a substitution and say, "The object-oriented example
or pattern" rather than the object-oriented paradigm, are we
gaining anything in understanding? I'm not so sure. It seems that
what we really mean to say is, the object-oriented software
development technique. But that may be just too big a mouthful,
and so we are stuck with paradigm.
Before object-oriented design, there was procedural design -- also
referred to as algorithmic design. The great procedural tool was
the flowchart. IF I get in my car, AND
I turn the key in the ignition, AND the car is fueled, THEN I can
drive it to Walmart to pick up cat food (which will make the cat
very happy). (Note: the automobile is a paradigm of
object-oriented metaphors. All experienced programmers have used
the automobile to describe object-oriented programming. It seems
to work, so what the hell.) So, with procedural programming, we
have to think about cause and event. What happens if I do this
after I have done that? That aspect of programming has not
disappeared. Not even from object-oriented programming.
There are more than two styles of programming, and for a given problem, one may be more
appropriate than another. This list is derived from
Grady Booch:
class Tree { | ||
public : | //"public" keyword is an access specifier | |
Tree( ); | //this is a constructor | |
virtual ~Tree( ); | //this is a virtual destructor | |
virtual unsigned int ageOfTree( ) = 0; | //this is a pure virtual function | |
virtual unsigned int sizeOfTree( ); | //this is a virtual function | |
protected : | //another access specifier | |
unsigned int treeAge; | //member data | |
unsigned int treeDiameter; | //member data | |
unsigned int treeHeight; | //member data | |
}; |
I'm going to get into things like virtual
functions and pure virtual functions
pretty soon. For now, let's say that you declare a function to be
virtual if you think another class will be derived from the class
in which it is declared. A pure virtual function basically
guarantees that a given class will be derived from whatever class
the pure virtual function appears in. This is because a class
that has one or more pure virtual functions cannot be
instantiated. (By the way, C programmers may be interested in
knowing that the only difference between a class and a struct (in
C++) is that a struct is public by default, whereas a class is
private by default.)
If we take the Tree class as our base class, then a pine tree might look something like this:
class Pine : public Tree{ | //this says a Pine "isa" Tree |
public : | ||
Pine( ); | //Pine's constructor | |
virtual ~Pine( ); | //another virtual destructor | |
virtual unsigned int ageOfTree( ); | ||
bool isDeciduous( const &Tree aTree ); | //isDeciduous is a member function that takes //a const reference to Tree and returns a bool |
|
private : | ||
unsigned int noOfBranches; | //is something anyone would want to know? | |
char someOtherTreeInfo; | //member data | |
}; |
So here is our first rather simple example of inheritance. In the first line of the declaration, we show that class Pine inherits all the non-private members of the Tree class. As you may have noticed, the base Tree class has no private members, so Pine inherits everything except the constructor. Constructors cannot be inherited and they cannot be declared to be virtual. However, it is possible to simulate a virtual constructor. Why you might want to do something like that is covered in James Coplien's Advanced C++. Because the Pine class is derived from the Tree class, and there are no private data or member functions in the Tree class, Pine gets the whole enchilada. There is no need to define a function sizeOfTree( ) because it exists in the base class. It is necessary, however, to define ageOfTree( ) because the base class declares that as a pure virtual function. That means that if you instantiate Pine, then you get a sizeOfTree( ) function. You also get treeAge, treeDiameter, and treeHeight. You don't get ageOfTree( ), but you will be forced to create such a function because pure virtual functions are placeholders. They tell whoever is extending the interface that ageOfTree( ) belongs in the interface of any class derived from Tree.
Let's forget the syntax and think about what we can achieve with inheritance. First, as just about every text book on object-oriented programming will tell you, a class that is derived from another class "is-a" (or "isa") type of that class. Thus, a Pine is-a Tree. (The reverse is not necessarily true; a Tree does not have to be a pine).