CSCI 207: Fundamentals of Data Structures & Algorithms: Review of Object Oriented Programming Basics
CSCI 207: Fundamentals of Data Structures & Algorithms: Review of Object Oriented Programming Basics
Algorithms
Lecture 2
Review of Object Oriented Programming Basics
1
Inheritance
▪ "A relationship amongst classes whereby one class shares the structure and/or
behaviour defined in one (single inheritance) or more (multiple inheritance) other
classes. Inheritance defines an "is-a" hierarchy among classes in which a member
class inherits from one or more super classes".
▪ The single most important rule in C++ object oriented programming is that public
inheritance means "is-a". Ignoring this rule is probably the most common cause of
poor design when developing a C++ application.
▪ This is an example of single inheritance, where class TStudent inherits the state
and behaviour from the TPerson class. The alternative relationship to "is-a" is "has-
a" e.g. a Person has-a name. The has-a relationship is achieved through the use of
layering, where an object is contained within another object.
2
Inheritance
▪ A Base class is a class from which another class inherits, e.g. TPerson is a base
class. A Derived class is a class that inherits from one or more classes, e.g. TStudent
is a derived class. Alternative Terms:
Super class = Base class
Sub class = Derived class
inherits = extends
▪ Let’s have a look at what we mean by inheriting state and behaviour of a class:
class TPerson
{
private:
// data members
char _Name[20];
char _Address[80];
public:
// Constructor
TPerson(const char* Name, const char *Address);
public:
// Constructor
TStudent(const char* Name, const char *Address, int DegreeCode);
// Selector function for class Student only
int DegreeCode() const { return _DegreeCode; }
};
4
Inheritance
TPerson Person("Fred", "Germany"); // Create a Person object
cout << Person.Name() << " lives in " << Person.Address() << endl;
A TPerson object is created and initialised by the class constructor. The selector
functions are then used to access the data members. The result as one expects is
"Fred lives in Germany"
TStudent Student("Bill", "UK", 5150); // Create a Student object
cout << Student.Name() << " lives in " << Student.Address() << ". Degree code = "
<< Student.DegreeCode() << endl;
A TStudent object is created and initialised by the class constructor. The selector
functions for both the TStudent class and the base class (TPerson class) are used to
access the data members within the class hierarchy. The result is "BilI lives in UK.
Degree code = 5150“
From this example the TStudent class is clearly an extension of the TPerson class.
Member functions from either class can be called for the TStudent object. The
converse is not true, it is a compiler error to call the member function DegreeCode()
on a TPerson object. 5
Inheritance
TPerson::TPerson(const char* Name, const char *Address)
{ if (strlen(Name) < sizeof(_Name))
strcpy(_Name, Name);
else
_Name[0] = 0;
The constructor for the TPerson class copies the name and address parameters to
the respective data members. To avoid duplication of this initialisation code, it would
be useful if the TPerson class constructor could be called from within the TStudent
class's constructor. This is achieved by using the constructors initialisation list.
TStudent::TStudent(const char* Name, const char *Address, int DegreeCode)
:TPerson(Name,Address),_DegreeCode(DegreeCode)
{} // CORRECT
The use of _Address produces a compiler error. The data member _Address is declared
private within class TPerson. A private member is not visible to derived class.
7
Binding
Let’s try and extend the TPerson and TStudent classes to include output streaming.
The member function Write() provides the output for the TPerson class’s data members.
We have overridden the Write() function within the TPerson class by placing a Write()
function within TStudent class. To reduce code duplication, TStudent::Write() calls
TPerson::Write() to output the TPerson class' data members.
8
Binding
TStudent Student("Bill", "UK", 5150);
Student.Write(cout);
Name: Bill
Address: UK
DegreeCode: 5150
This example illustrates that a member function within a base class can be overridden
by the declaration of a member function within the derived class, provided that both
functions have the same identity (i.e. name, number and type of parameters and
whether constant or not).
9
Binding
"Binding denotes the association of a name (e.g. a function call) with a class.” We will
now consider the case of pointers.
TPerson *Ptr;
Ptr = new TStudent("Anne", "UK", 5151);
Ptr->Write(cout); // Output Name: Anne Address: UK
delete Ptr;
Ptr to a TPerson object can point to TStudent object. The C++ language permits this
syntax only because TPerson is above TStudent in the same object hierarchy, i.e.
TStudent is derived either directly or indirectly from TPerson. Assuming both classes
have function Write(), which of the two Write member functions are called?
For non-virtual functions (i.e. standard functions) the compiler determines which
function to call at compile time. This process is known as static binding. At compile
time, the only information available to the compiler is that Ptr is of type
TPerson*. The compiler therefore determines that the Write() function call is
associated with TPerson class and statically binds the call to TPerson::Write()
10
Virtual Functions
"An operation upon an object. A virtual function may be defined by derived classes;
thus for a given object, it is implemented through a set of methods declared in various
classes that are related via the inheritance hierarchy." Virtual functions inform the
compiler to perform dynamic binding on the function call.
In C++, a virtual function is denoted by the virtual keyword preceding the function
declaration in the class declaration.
class TPerson
{
virtual ostream &Write(ostream &out) const;
};
At runtime, the type of the object pointed to by Ptr is determined and cross
referenced in the virtual table to give, in this case, the function TStudent::Write()
11
Virtual Functions
When Write() is made a virtual function, the output from the above example
changes to:
Name: Anne
Address: UK
DegreeCode: 5151
The use of a non‐virtual function in the previous example is obviously incorrect and
can give some surprising results.
12
Virtual Functions
//Simple list containing five people is created. A loop writes each object in turn.
TPerson *List[5]; // List is an array of pointers to TPerson objects
List[0] = new TStudent("Bill", "UK",5150);
List[1] = new TPerson("Fred", "Germany");
List[2] ‐ new TStudent("Anne", "UK",5151);
List[3] = new TPerson("Mary", "France");
List[4] = new TPerson("Tom", "UK");
delete List[4];
...
delete List[0];
This simple example illustrates the power of the virtual functions and the inheritance
mechanism. A heterogeneous list of objects is created and the compiler automatically
determines the appropriate Write() function to call.
Virtual functions appear very powerful, but there is an overhead. The virtual mechanism
relies on dynamic binding which by its nature impacts on the application performance.
13
Polymorphism
Polymorphism = the ability to take on many forms.
Usually polymorphism refers to the ability to redefine methods for derived classes.
For example, given a base class TShape, polymorphism enables the programmer to
define different Area() member functions for any number of derived classes, such as
circles, rectangles and triangles.
You can define an object as of type TShape and later specify that this particular object
is a rectangle. No matter what shape an object is, applying the Area() method to it
will return the correct results.
14
Inheritance ‐ Abstract Classes
The form of inheritance used in the TPerson / TStudent example is an illustration of
"inheritance of the implementation". The Student class inherited the implementation
of the data members and member functions ( e.g. _Name and Name() ) from the
TPerson class.
15
Inheritance ‐ Abstract Classes
"An abstract class has no objects. An abstract class is written with the expectation that
its concrete derived classes will add to its structure and behaviour, typically by
implementing its abstract operations.“
A class is abstract if it contains one or more pure virtual functions. A pure virtual
function is a function that is declared virtual and has no definition.
class TShape
{
virtual void Draw() = 0;
...
};
...
TShape Shape; // Compiler Error
TShape class is effectively saying that here is an interface Draw() for any object of type
TShape, but I have no idea how it should be implemented. Avoid the declaration of data
members within an abstract class as this provides some degree of implementation. 16
Thank You
Questions?
17