Download presentation
Presentation is loading. Please wait.
Published byDoreen Lindsey Modified over 9 years ago
1
EE4E. C++ Programming Lecture 3 Inheritance and Polymorphism
2
Contents Introduction Introduction Base classes and derived classes Base classes and derived classes Initializing derived class objects Initializing derived class objects Protected class members Protected class members Towards polymorphism – pointers and references to objects Towards polymorphism – pointers and references to objects Polymorphism Polymorphism Abstract classes Abstract classes Polymorphism and OOP Polymorphism and OOP
3
Introduction Inheritance is a fundamental requirement of oriented programming Inheritance is a fundamental requirement of oriented programming It allows us to create new classes by refining existing classes It allows us to create new classes by refining existing classes Essentially a derived class can inherit data members of a base class Essentially a derived class can inherit data members of a base class The behaviour of the derived class can be refined by redefining base class member functions or adding new member function A key aspect of this is polymorphism where a classes behaviour can be adapted at run-time
4
Base classes and derived classes We can think of many examples in real life of how a (base) class can be refined to a set of (derived) classes We can think of many examples in real life of how a (base) class can be refined to a set of (derived) classes For example a Polygon class can be refined to be a Quadrilateral which can be further refined to be a Rectangle For example a Polygon class can be refined to be a Quadrilateral which can be further refined to be a Rectangle We can think of these classes as following an IS-A relationship We can think of these classes as following an IS-A relationship A Quadrilateral IS-A Polygon A Rectangle IS-A Quadrilateral
5
We can think of lots of other possible examples of base/derived classes We can think of lots of other possible examples of base/derived classes Base class Derived class Shape Triangle, Circle, Rectangle Account Current, Deposit Student Undergraduate, Postgaduate Vehicle Car, Truck, Bus Filter Lowpass, Bandpass, Highpass
6
Example An Account base class models basic information about a bank account An Account base class models basic information about a bank account Account holder Account number Current balance Basic functionality Basic functionality Withdraw money Deposit money
7
class Account {private: int account_number; char* account_holder; int balance; public: Account(int, char*,int); void withdraw(int amount) { if (balance>amount) balance-=amount;} void deposit(int amount) { balance+=amount;} };
8
We can consider refinements to our Account class We can consider refinements to our Account class CurrentAccount Can have an overdraft facility No interest paid DepositAccount Pays interest on any balance No overdraft facility
9
We will create our refined classes using public inheritance from the Account base class We will create our refined classes using public inheritance from the Account base class Classes CurrentAccount and DepositAccount inherit the basic attributes (private members) of account Classes CurrentAccount and DepositAccount inherit the basic attributes (private members) of account account_number account_holder balance Also, new attributes are added Also, new attributes are added CurrentAccount::overdraft_facility DepositAccount::interest_rate
10
class CurrentAccount : public Account {private: int overdraft_facility; public: CurrentAccount(int, char*, int, int); void withdraw(int); // Takes account of overdraft // facility };
11
class DepositAccount : public Account {private: float interest_rate; public: DepositAccount(int, char*, int, float); float calc_interest(); // Calculates interest based // on the current balance };
12
CurrentAccountDepositAccount account_number account_holder balance deposit() withdraw() overdraft_facility withdraw() interest_rate calc_interest() account_number account_holder balance deposit() withdraw()
13
In class CurrentAccount, the member function withdraw() is overridden In class CurrentAccount, the member function withdraw() is overridden This will be a crucial aspect of object oriented programming as we shall see later Polymorphism Also, a new member function, calc_interest() is defined in DepositAccount Also, a new member function, calc_interest() is defined in DepositAccount This is an example of a derived class extending a base class
14
Before we can finish implementing the derived classes, we need to consider private/public access Before we can finish implementing the derived classes, we need to consider private/public access Key point 1 Key point 1 In public inheritance, public member functions of the base class become public member functions of the derived class
15
Thus in our example, the following are public member functions and can be called from outside of the class Thus in our example, the following are public member functions and can be called from outside of the class CurrentAccount::withdraw() CurrentAccount::deposit() DepositAccount::withdraw() DepositAccount::deposit()
16
Key point 2 Key point 2 Private members of the base class can not be accessed from the derived class Obvious otherwise encapsulation could be easily broken by inheriting from the base class Begs the question, how do we initialise derived class objects? We can see how this is done by implementing the constructors of DepositAccount and CurrentAccount
17
Account::Account(int acc_no, char* acc_holder, int b) {account_number=acc_no;strcpy(acc_holder,account_holder);balance=b;} DepositAccount::DepositAccount(int acc_no, char* acc_holder, int b, float int_rate):Account(acc_no, acc_holder, b) {interest_rate=int_rate;} CurrentAccount::CurrentAccount(int acc_no, char* acc_holder, int b, int ov_facility):Account(acc_no, acc_holder, b) {overdraft_facility=ov_facility;}
18
Thus derived class constructors are implemented by first calling the base class constructor and then initializing specific derived class private data members Thus derived class constructors are implemented by first calling the base class constructor and then initializing specific derived class private data members Uses the following syntax: Uses the following syntax: MyDerivedClass::MyDerivedClass(int arg1, int arg2, int arg3):MyBaseClass(arg1, arg2) { // Initialize additional private data member using arg3 }
19
Protected class members A protected class member is one that can be accessed by public member functions of the class as well as public member functions of any derived class A protected class member is one that can be accessed by public member functions of the class as well as public member functions of any derived class Its half way between private and public Encapsulation is then broken for classes in the inheritance hierarchy and thus must be used where performance issues are critical
20
Consider the implementation of CurrentAccount::withdraw() and DepositAccount::calc_interest() Consider the implementation of CurrentAccount::withdraw() and DepositAccount::calc_interest() void CurrentAccount::withdraw(int amount) { // Needs to access and update Account::balance } float DepositAccount::calc_interest() { // Needs to access and update Account::balance }
21
Making Account::balance protected removes the need for Account::get_balance() and Account::set_balance() access functions Making Account::balance protected removes the need for Account::get_balance() and Account::set_balance() access functions class Account {private: int account_number; char* account_holder; protected: int balance; public: Account(int, char*,int); void withdraw(int amount) { balance-=amount;} void deposit(int amount) { balance+=amount;} };
22
void CurrentAccount::withdraw(int amount) { if ((balance-amount)>-overdraft_facility) balance-=amount;} float DepositAccount::calc_interest() { float interest=balance*interest_rate; balance+=interest; return interest; }
23
We can summarise private/protected/public access in the following table We can summarise private/protected/public access in the following table Class member Can be accessed from private public member functions of same class protected public member functions of same class and derived classes publicAnywhere
24
Towards polymorphism – pointers and references to objects A key aspect of object oriented programming is polymorphism A key aspect of object oriented programming is polymorphism The ability to reference objects which show different behaviour Polymorphism is implemented through pointers and references to objects Polymorphism is implemented through pointers and references to objects
25
We can set up a pointer (or a reference) to an object very easily We can set up a pointer (or a reference) to an object very easily Account acc(12345, “J. Smith”, 100); Account* p_acc=&acc; p_acc Account 12345 J Smith 100 deposit() withdraw()
26
Key point Key point Because of the IS-A relationship, we can point a base class pointer at derived class objects – but not vice versa An DepositAccount object is a Account object An CurrentAccount object is a Account object DepositAccount dep_acc(12345, “J. Smith”, 100,5.0); Account* p_acc = &dep_acc;//OK
27
p_acc DepositAccount 5.0 calc_interest() 12345 J Smith 100 deposit() withdraw()
28
But we can’t point a derived class pointer at a base class object But we can’t point a derived class pointer at a base class object An Account object is not (necessarily) a DepositAccount object Account acc(12345, “J. Smith”, 100); DepositAccount* p_dep_acc = &acc;//Error!
29
Polymorphism Polymorphism is the key concept in object oriented programming Polymorphism is the key concept in object oriented programming First we will look at the mechanics of polymorphism using our simple example classes First we will look at the mechanics of polymorphism using our simple example classes We will then look at how polymorphism lends itself to OOP as well as the advantages over a procedural approach We will then look at how polymorphism lends itself to OOP as well as the advantages over a procedural approach
30
We can see from the CurrentAccount class that CurrentAccount::withdraw() overrides Account::withdraw() We can see from the CurrentAccount class that CurrentAccount::withdraw() overrides Account::withdraw() CurrentAccount account_number account_holder balance deposit() withdraw() overdraft_facility withdraw() overridden
31
Consider the following code Consider the following code CurrentAccount curr_acc(12345, “J. Smith”, 100,500); Account* p_acc = &curr_acc;//OK p_acc->withdraw(250);// Which withdraw()
32
account_number account_holder balance deposit() withdraw() overdraft_facility withdraw() p_acc CurrentAccount Which one is called?
33
Because p_acc has been declared as Account*, Account::withdraw() is called Because p_acc has been declared as Account*, Account::withdraw() is called Incorrect behaviour as p_acc points to a CurrentAccount object Incorrect behaviour as p_acc points to a CurrentAccount object CurrentAccount curr_acc(12345, “J. Smith”, 100, 500); Account* p_acc = &curr_acc; p_acc->withdraw(250);// Calls Account::withdraw() // Ignores overdraft facility
34
The solution is to make Account::withdraw() a virtual function so that dynamic binding takes place The solution is to make Account::withdraw() a virtual function so that dynamic binding takes place The derived class member function CurrentAccount::withdraw() is actually called and correct behaviour is observed Changes to the definition of the Account class are minimal Changes to the definition of the Account class are minimal
35
class Account {private: int account_number; char* account_holder; protected: int balance; public: Account(int, char*,int); virtual void withdraw(int amount) { balance-=amount;} void deposit(int amount) { balance+=amount;} };
36
Abstract classes In our example classes, Account::withdraw() was declared as a virtual function In our example classes, Account::withdraw() was declared as a virtual function We were able to provide a sensible implementation of this function This implementation could be regarded as default behaviour if the function was not overridden in derived classes
37
CurrentAccount curr_acc(12345, “J. Smith”, 100, 500); DepositAccount dep_acc(56789, “J. Smith”, 100, 5.0); Account* p_acc_curr = &curr_acc; Account* p_acc_dep = &dep_acc; p_acc_curr->withdraw(250);// Account::withdraw() // overridden by // overridden by // CurrentAccount::withdraw() // CurrentAccount::withdraw() p_acc_dep->withdraw(250);// Account::withdraw() // called // called
38
Abstract classes arise when there is no sensible implementation of the virtual functions in the base class Abstract classes arise when there is no sensible implementation of the virtual functions in the base class Base class virtual functions are always overridden by derived class implementations In this case, we simply assign the base class virtual functions to zero In this case, we simply assign the base class virtual functions to zero They become pure virtual functions A class containing at least one pure virtual function is an abstract class
39
As an example, suppose we wanted to design a hierarchy of shape classes for a computer graphics application As an example, suppose we wanted to design a hierarchy of shape classes for a computer graphics application class Shape {public: virtual void draw()=0; virtual float area()=0; };
40
Shape is an abstract concept and there are no sensible definitions of Shape::draw() and Shape::area() Shape is an abstract concept and there are no sensible definitions of Shape::draw() and Shape::area() They are assigned to zero and hence are pure virtual functions This makes Shape an abstract class We cannot declare Shape objects Derived objects of Shape can be created and implementations of the pure virtual functions provided Derived objects of Shape can be created and implementations of the pure virtual functions provided
41
class Square : public Shape {private: int x_pos, y_pos; int side; public: Square(int x, int y, int length) { x_pos=x; y_pos=y; side=length;} void draw() {// Call graphics commands …} float area() { return side*side}; };
42
class Circle : public Shape {private: int x_cent, y_cent; int radius; public: Circle(int x, int y, int r) { x_cent=x; y_cent=y; radius=r;} void draw() {// Call graphics commands …} float area() { return 3.14159*radius*radius;} };
43
The pure virtual functions in Shape are always overridden in the derived class through polymorphism The pure virtual functions in Shape are always overridden in the derived class through polymorphism void main() { Shape s;// Error! Can’t create a Shape object Shape* sp=new Square(5,6,20);// OK sp->draw();// Calls Square::draw() float a=sp->area();// Calls Square::area() };
44
We can regard abstract classes as a ‘glue’ which binds related classes together and where we don’t have to worry about implementational details We can regard abstract classes as a ‘glue’ which binds related classes together and where we don’t have to worry about implementational details They just have to present a common interface Shape CircleSquareTriangle draw() area()
45
Polymorphism and OOP We can easily conceive of an application where a heterogenous list (or array) of shape objects are manipulated We can easily conceive of an application where a heterogenous list (or array) of shape objects are manipulated For example, in a CAD system, a complex drawing may comprise a list of basic shapes For example, in a CAD system, a complex drawing may comprise a list of basic shapes Each object on the list may exhibit different behaviour (for example may draw itself differently) but the application user need not worry about this Each object on the list may exhibit different behaviour (for example may draw itself differently) but the application user need not worry about this Polymorphism looks after it
46
Example Example A hetereogenous list of shapes (accessed an array of Shape pointers) can each be drawn This could be a means of drawing a complex shape from simpler sub-shapes Shape** s s[0]s[1] ….. s[2]s[3]s[4] draw()
47
void main() { Shape** s = new Shape*[5]; s[0]=new Square(0,0,5); s[1]=new Circle(2,4,3); s[2]=new Circle(3,1,6); s[3]=new Square(2,5,3); s[4]=new Square(2,6,7); for (int j=0; j<5; j++) s[j]->draw();// Draws each shape on the list };
48
So what’s the advantage of doing it this (OOP) way? So what’s the advantage of doing it this (OOP) way? Suppose we want to extend our list of ‘sub-shapes’ Suppose we want to extend our list of ‘sub-shapes’ We simply derive any new shape from Shape and add the required functionality to the virtual functions draw() and area() The code for the for loop doesn’t change Polymorphism automatically invokes the correct behaviour
49
class Triangle : public Shape {private: int x_vertices[3], int y_vertices[3]; public: Triangle(int[] xv, int[] yv) {…} void draw() {…} float area() {..} }; void main() {… for (int j=0; j<5; j++) for (int j=0; j<5; j++) s[j]->draw();// Draws each shape on the list }
50
And finally….. Polymorphism is the critical component in object oriented systems Polymorphism is the critical component in object oriented systems C++ supports this with the virtual function C++ supports this with the virtual function In Java, all inherited member functions are virtual Its important to understand how this leads to extendible applications as new objects exhibiting new behaviours can be easily introduced Its important to understand how this leads to extendible applications as new objects exhibiting new behaviours can be easily introduced
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.