SlideShare a Scribd company logo
1 of 10
Inheritance or (class derivation) in C++
Inheritance is an idea from semantic networks in AI: e.g., robin ISA bird (draw)
• a class inherits attributes from a superclass: e.g., robin inherits haspart wings from bird
• Inheritance can thus be a way to model subtype relationships
• e.g., a popUpMenu ISA Menu:
• Inheritance becomes a way to get more code reuse:
• e.g., popUpMenu inherits routines such as choosing options from Menu
• Inheritance becomes a way to extend an existing class slightly:
• Or, in handout, vecRange ISA vector plus lower & upper bounds & range checking
• e.g., vecRange allows v(-2) if lowerbound of v is -2 or less
In C++, inheritance is called class derivation and looks like this:
class vecRange : public vector {
int lwb, upb; //lower and upper bounds
public:
vecRange(int,int); //a constructor for vecRange class
int& operator[] (int); //overloading array access operator
}
• vecRange is a derived class, vector is a base class
• Derivation assumes that base class, vector, already exists!
• vector's data allocates an int array of size sz
• vector's public member functions include assignment, plus:
int& vector::operator[](int i) { return *(v+i); }
• vecRange will reuse as much of vector's code as possible
• vecRange can also add new code, e.g.: overloaded operator[]:
• vecRange's operator[] is overloading, and calling vector's operator[]
Inheritance implies more ways to control access to class members
• public keyword in derivation makes base class's members accessible to clients of
vecRange
• contrast with public: (with colon) which makes derived class's members accessible
• private base-class prevents clients of derived class from accessing base class members
• When might this come in handy? Suppose we wanted to derive Stack from vector?
• Shouldn't Stack prevent its clients from having array-like access?
So: Stack : private vector { //... }; --hides operator[], etc. from Stack's
clients
• C++ idiom: use private class derivation (or composition) for implementation reuse
• Use public class derivation for subtype relations,
e.g., vecRange : public vector { //... };
Suppose we want to provide access to subtypes but not world at large?
• e.g., suppose vecRange wants to access a data member of its base class, v or sz?
• since these are declared private in vector, they are inaccessible, even to derived classes!
1
• enter another keyword: protected: in lieu of public: and private:, in class
declaration
• means that derived classes, such as vecRange, have access, but clients of class still don't
2
/*----------------------- atm_oop.h: ATM machine ------------------*/
#include <iostream.h>
#include "Lstring.h"
//Account generalizes checking, savings, etc.
class Account {
public:
int getPIN() const; //extract PIN
void setPIN(int PIN); //insert PIN
//PIN must have four digits
float getBalance() const; //extract balance
void setBalance(float); //insert balance
//balance must be non-negative
float addToDeposits(float); //today's deposits
float getDeposits(); //extract deposits
float subFromBalance(float); //withdraw from balance
bool sufficientBalance(float); //can cover amount?
const Lstring& getType(); //extract accountType
void setType(Lstring); //insert accountType
private: //note: hiding data, even from derived classes
int PIN; //Personal Identification Number
float balance; //not including today's deposits
float deposits; //today's deposits
protected: //accessible to derived classes but not clients
Lstring accountType; //"checking", "savings"...
Account(); //default constructor called by derived classes
};
//For ATM, Checking and Savings add very little to Account
class Checking : public Account {
public:
Checking(int PIN,float balance);
Checking(); //default constructor
}; //class Savings : public Account { ... }, similarly
/*-------------------- excerpts from atm_oop.cpp ------------------*/
int Account :: getPIN() const { return PIN; } //extract PIN
void Account :: setPIN(int pin) //insert PIN
{ assert(pin >= 1000 && pin <= 9999); //PIN must be 4 digits
PIN = pin;
} //getBalance() and setBalance are similar
float Account :: subFromBalance(float withdraw)
{ assert(balance > withdraw); balance = balance - withdraw; }
bool Account :: sufficientBalance(float amount) //cover subtraction?
{ return (balance >= amount); }
//Constructor is protected; only call derived class constructors
Account :: Account () //default constructor
{ deposits = 0; } //today's balance start off zero
//Checking and Savings add very little to Account
//... constructors just add Lstring accountType
Checking :: Checking(int PIN,float balance)
{ setPIN(PIN);
setBalance(balance);
setType("checking");
3
}
Checking :: Checking() {} //default
4
Discussion of ATM example excerpts:
• base class, Account, captures the commonality between Checking and Savings
How does this commonality set up further extensions of the ATM system?
(possibly other) types of bank accounts
• All the new derived classes need to do is set up constructors
which can in turn invoke functions like setType() and setBalance() of Account.
• Base class Transaction (not shown, but available in atm_oop.h)
captures the common features of derived classes Deposit and Withdrawal,
all three of which are active clients of Account.
• Note that the constructor for Account is protected:
• so that clients cannot directly construct instances of Account,
but rather just derived classes, such as Checking.
Discussion of the implementation of some of the members of the Account classes:
• What do the assertions accomplish? (protect the meaning of Account data)
One requires that a given PIN have four digits,
another (not shown) makes sure that a starting balance is non-negative, etc.
While members of Account enforce these constraints,
the responsibility for observing them belongs to clients of these functions,
elsewhere in the ATM system.
• These clients (such as those in the Transaction hierarchy) must not pass the buck
to human clientsCwho aren=t interested in seeing the assertion failure error messages!
What=s the difference between the if test in sufficientBalance()
and the assertion in subFromBalance()?
A client such as Withdrawal should test sufficientBalance()Cand display a firm
but friendly message to the userCbefore attempting subFromBalance().
• The constructors in this little hierarchy are also interesting.
The base class, Account, just initializes one data member, deposits, to zero.
Since this constructor is protected, it can safely assume that derived class constructor
will properly initialize the remaining data.
• Checking has two constructors (Savings also has two, not shown, nearly the same.)
The first constructor takes two arguments & initializes most of the members of its base
class. Function setType() takes an Lstring which distinguishes different subtypes of
Account
( useful for printing messages to the user).
What about the second constructor, which doesn=t appear to do anything?
The compiler needs a default constructor (with no parameters)
in order to instantiate objects of a class.
The compiler is quite willing to create a default constructor automatically
(a facility which a few other simple classes in the ATM system take advantage of),
but not if a class already has defined another constructor.
So Checking needs an explicit default constructor,
which gets called to set up the members of this class
(mostly by invoking the constructor for the base class, Account)
before executing the body of its two-parameter constructor.
As you can see, the behavior of C++ code can be subtle!
5
Suppose we derived another class from Stack, say, Staque
• Would Staque have access to members of vector? Take a guess...
• No: because private derivation means private to all except the immediately derived class
• To anticipate this possibility, there is an intermediate access level of derived class access
Stack : protected vector {//...};
• Now Staque, derived from Stack, can also access vector's members
• Suppose Stack has a private member, top, which Staque should see, but not any
clients
In Stack, instead of private:, use protected:
Lots and lots of access optionsCwhich designers must anticipate!
Here's another option: suppose you want to let clients of Stack use vector's size() function:
public: int size; //function size from base class is hereby visible to clients
Dynamic binding in C++
Another key idea of object-oriented programming is dynamic binding
• In fact, some say OOP = ADT + inheritance + dynamic binding
• defer binding of a name to a type until runtime
• another name for this capability is runtime polymorphism:
a different function can mean different things at runtime
Handout: Shape is an abstract class: has center, color and some routines
• Shape declares draw() and move(Point) as virtual
• This keyword tells C++ to routines support dynamic binding
• meaning of these functions can vary at run-time
• can bind draw() to any subclass that overloads it, e.g. Circle
• Shape supplies a default definition for move(Point)
• derived classes can overload this function, but don't have to
• Shape also defines draw() as virtual draw()=0; --denotes a pure virtual function
• derived classes must (ultimately) define a pure virtual function!
• a class that includes a pure virtual function is an abstract class
• an abstract class may not have a constructor (no instances of this class)
• If you can't create an instance of an abstract class, what is it good for?
• Abstraction, of course: generalizing about effective classes
• Besides, you can assign an instance of a derived class to an abstract class
• Triangle and Circle are derived from Shape
• both inherit center, color data members, and where function
• but both overload draw() routines: why?
• What does dynamic binding buy us? More flexibility and more extensibility
6
Suppose we wanted to have a heterogeneous vector?
• e.g., suppose we wanted a vector of Shapes: Circles, Squares, etc.
Shape* shapes[10]; --Compiler can allocate pointers at shapes
• next two lines create a Circle and a Triangle and put them in shapes
• then we loop through the array
• What does shapes[0]->draw() do? What about shapes[1]->draw()?
• If we didn't have dynamic binding, how could distinguish between shapes?
• add a member to Shape identifying its type, say, shapeType
• let each derived class's constructor intialize shapeType
• add a switch statement distinguishing on shapeType:
switch (shapes[i]->shapeType) {
case Triangle: shapes[i]->drawTriangle();
case Circle: shape[i]->drawCircle();
//...
}
• What's the drawback of this switch technique?
• you'll need switch statements wherever you need to distinguish subclasses
• harder to extend, if you want to add a new derived class to Shapes hierarchy
then you'll have to modify all these switch statements!
Note: if you want dynamic binding, then you must specify the modifier, virtual!
• Non-virtual functions are the default
• Virtual functions have a small amount of runtime overhead
computing offset to function in a table (called the Vtbl) at runtime
• C programmers can be happy: OOP won't cost you anything unless you want it!
• Contrast Eiffel, Smalltalk and Objective-C, for which dynamic binding is the default
• Tradeoff between efficiency of C++
vs. runtime checking (and flexibility) of smalltalk or Objective-C
• Why might C++ approach get in the way of extensibilty (Open-Closed Principle)?
How do you know whether or how someone might want to extend your class?
Design for reusability has to anticipate this possibility by making functions virtual
Virtual destructors
Suppose some of the classes in the Shape hierarchy had members pointing into heap
So at least some these classes need their own destructors
Now, suppose I want to clean up the objects I assigned to the array, shapes?
Does anyone see a problem here?
We'd rather not have to figure out which destructor to call--another switch statement!
Looks like a job for a virtual destructor, e.g., in class Shape:
virtual ~Shape() {}
Then, when we run the Shape destructor, e.g.:
for (int i=0; i < 10; i++) delete *shapes[i];
Now the runtime system automatically runs the right destructor!
C++ idiom: if there any virtual functions in a base class, define a virtual destructor, too
7
Multiple inheritance
Single inheritance restricts class derivation to a hierarchy (tree)
Smalltalk and Objective-C only support single inheritance (though there are work-
arounds)
But sometimes the world doesn't map into a neat heiarchy
e.g., lions are carnivores, and lions are zoo animals
But are all carnivores zoo animals? Or are all zoo animals carnivores?
C++ (starting with 2.0) introduces the possibility of deriving from more than one base class
class ZooAnimal {//...};
class Carnivore {//...};
class Herbivore {//...};
class Lion: public ZooAnimal, protected Carnivore {};
• derivation can specify a list of base classes
• an instance of Lion inherits features from both ZooAnimal and Carnivore
Very nice, but multiple inheritance can also complicate things! Any idea why?
Name collisions--what if two parent classes have a member (feature) with the same name?
Suppose two different base classes use the same name:
e.g., suppose both ZooAnimal & Carnivore include a member function, locate()
Using the name is ambiguous and results in a compile time error
Disambiguate by using the class scope operator:
Lion::locate() //Encapsulate & invokes both members
{ ZooAnimal::locate(); Carnivore::locate(); }
Suppose a class can derive from the same base class in multiple ways?
class Panda: public Bear,public Bear; //illegal--unresolvable
ambiguity!
But zoologlists debate about whether Panda properly belongs to Bear or Racoon families:
class Panda: public Bear,public Racoon; //both derive from
ZooAnimal
ZooAnimal
/ 
Bear Racoon
/ 
Panda Panda
Question: does class Panda get one representation of base class ZooAnimal, or two?
By default, C++ generates two ZooAnimal base class parts for a Panda, e.g.:
--------------- Here's how a Panda gets built:
ZooAnimal part runs ZooAnimal() constructor for Bear()
- - - - - - - -
Bear Part runs Bear() constructor
---------------
ZooAnimal part runs ZooAnimal() constructor for Racoon()
- - - - - - - -
Racoon part runs Racoon() constructor
---------------
Panda part runs Panda() constructor--derived class is last
8
---------------
Suppose ZooAnimal has a member, e.g., locate()--how do we invoke it from Panda?
Once more, use class scope operator, e.g.:
Panda::locate()
{ return ( (isA() == BEAR)) //isA is home-brewed RTTI
? Bear::locate : Racoon::locate() ) ;
} //Intermediate base class disambiguates which ZooAnimal member to use
Suppose we want don't want duplicate, ambiguous base classes?
Then declare virtual base classes:
class Bear: public virtual ZooAnimal {//...};
class Racoon: virtual public ZooAnimal {//...};
class Panda: public Bear,private Racoon; //both derive from ZooAnimal
Panda p; p.locate(); //p has just one ZooAnimal; invokes unique
ZooAnimal::locate()
Note: shared virtual base class uses most accessible level of protection
9
---------------
Suppose ZooAnimal has a member, e.g., locate()--how do we invoke it from Panda?
Once more, use class scope operator, e.g.:
Panda::locate()
{ return ( (isA() == BEAR)) //isA is home-brewed RTTI
? Bear::locate : Racoon::locate() ) ;
} //Intermediate base class disambiguates which ZooAnimal member to use
Suppose we want don't want duplicate, ambiguous base classes?
Then declare virtual base classes:
class Bear: public virtual ZooAnimal {//...};
class Racoon: virtual public ZooAnimal {//...};
class Panda: public Bear,private Racoon; //both derive from ZooAnimal
Panda p; p.locate(); //p has just one ZooAnimal; invokes unique
ZooAnimal::locate()
Note: shared virtual base class uses most accessible level of protection
9

More Related Content

What's hot

What's hot (19)

Java RMI
Java RMIJava RMI
Java RMI
 
Presentation to java
Presentation  to  javaPresentation  to  java
Presentation to java
 
Java Programming
Java ProgrammingJava Programming
Java Programming
 
Java Tutorial | My Heart
Java Tutorial | My HeartJava Tutorial | My Heart
Java Tutorial | My Heart
 
Java tutorial PPT
Java tutorial PPTJava tutorial PPT
Java tutorial PPT
 
Introduction to java Programming
Introduction to java ProgrammingIntroduction to java Programming
Introduction to java Programming
 
Java Tutorial
Java TutorialJava Tutorial
Java Tutorial
 
Java tutorial for Beginners and Entry Level
Java tutorial for Beginners and Entry LevelJava tutorial for Beginners and Entry Level
Java tutorial for Beginners and Entry Level
 
Introduction to c#
Introduction to c#Introduction to c#
Introduction to c#
 
Java Tut1
Java Tut1Java Tut1
Java Tut1
 
Unit 2 Java
Unit 2 JavaUnit 2 Java
Unit 2 Java
 
Introduction to java 101
Introduction to java 101Introduction to java 101
Introduction to java 101
 
Learn Java Part 2
Learn Java Part 2Learn Java Part 2
Learn Java Part 2
 
C#ppt
C#pptC#ppt
C#ppt
 
Core Java Tutorials by Mahika Tutorials
Core Java Tutorials by Mahika TutorialsCore Java Tutorials by Mahika Tutorials
Core Java Tutorials by Mahika Tutorials
 
Scala Reflection & Runtime MetaProgramming
Scala Reflection & Runtime MetaProgrammingScala Reflection & Runtime MetaProgramming
Scala Reflection & Runtime MetaProgramming
 
Introduction To C#
Introduction To C#Introduction To C#
Introduction To C#
 
Lambda: A Peek Under The Hood - Brian Goetz
Lambda: A Peek Under The Hood - Brian GoetzLambda: A Peek Under The Hood - Brian Goetz
Lambda: A Peek Under The Hood - Brian Goetz
 
Java Notes
Java Notes Java Notes
Java Notes
 

Viewers also liked

Viewers also liked (18)

#AFCKesha
#AFCKesha#AFCKesha
#AFCKesha
 
Faltantes
FaltantesFaltantes
Faltantes
 
Ingrid Visser's Visit!
Ingrid Visser's Visit!Ingrid Visser's Visit!
Ingrid Visser's Visit!
 
Relational model
Relational modelRelational model
Relational model
 
De draak in groente en fruit!
De draak in groente en fruit!De draak in groente en fruit!
De draak in groente en fruit!
 
Relational model
Relational modelRelational model
Relational model
 
Automobilnik
 Automobilnik Automobilnik
Automobilnik
 
management
managementmanagement
management
 
Book week
Book weekBook week
Book week
 
Relational model
Relational modelRelational model
Relational model
 
De draak!!!
De draak!!!De draak!!!
De draak!!!
 
Now Hiring PowerPoint
Now Hiring PowerPointNow Hiring PowerPoint
Now Hiring PowerPoint
 
Foto estafette 2012-2013
Foto estafette 2012-2013Foto estafette 2012-2013
Foto estafette 2012-2013
 
Internship Reort presentation (Sajid Aslam)
Internship Reort presentation (Sajid Aslam) Internship Reort presentation (Sajid Aslam)
Internship Reort presentation (Sajid Aslam)
 
Pure Diamond Investments Presentation
Pure Diamond Investments PresentationPure Diamond Investments Presentation
Pure Diamond Investments Presentation
 
Asosiasi bunyi
Asosiasi bunyiAsosiasi bunyi
Asosiasi bunyi
 
Development of GM Crops (Methods) against insect diversity
Development of GM Crops (Methods) against insect diversityDevelopment of GM Crops (Methods) against insect diversity
Development of GM Crops (Methods) against insect diversity
 
redacción
redacciónredacción
redacción
 

Similar to C++ Inheritance Class Derivation Explained

Similar to C++ Inheritance Class Derivation Explained (20)

C#2
C#2C#2
C#2
 
Csharp_mahesh
Csharp_maheshCsharp_mahesh
Csharp_mahesh
 
object oriented programming language.pptx
object oriented programming language.pptxobject oriented programming language.pptx
object oriented programming language.pptx
 
UNIT3 on object oriented programming.pptx
UNIT3 on object oriented programming.pptxUNIT3 on object oriented programming.pptx
UNIT3 on object oriented programming.pptx
 
Advanced programming topics asma
Advanced programming topics asmaAdvanced programming topics asma
Advanced programming topics asma
 
Presentation 1st
Presentation 1stPresentation 1st
Presentation 1st
 
Constructor
ConstructorConstructor
Constructor
 
OOP
OOPOOP
OOP
 
Oops concept on c#
Oops concept on c#Oops concept on c#
Oops concept on c#
 
Introduction to c_plus_plus
Introduction to c_plus_plusIntroduction to c_plus_plus
Introduction to c_plus_plus
 
Introduction to c_plus_plus (6)
Introduction to c_plus_plus (6)Introduction to c_plus_plus (6)
Introduction to c_plus_plus (6)
 
LEARN C#
LEARN C#LEARN C#
LEARN C#
 
Learn C# at ASIT
Learn C# at ASITLearn C# at ASIT
Learn C# at ASIT
 
Synapseindia dot net development
Synapseindia dot net developmentSynapseindia dot net development
Synapseindia dot net development
 
Vectors Intro.ppt
Vectors Intro.pptVectors Intro.ppt
Vectors Intro.ppt
 
Inheritance
InheritanceInheritance
Inheritance
 
Presentation 3rd
Presentation 3rdPresentation 3rd
Presentation 3rd
 
c++-language-1208539706757125-9.pdf
c++-language-1208539706757125-9.pdfc++-language-1208539706757125-9.pdf
c++-language-1208539706757125-9.pdf
 
Basics of objective c
Basics of objective cBasics of objective c
Basics of objective c
 
8abstact class in c#
8abstact class in c#8abstact class in c#
8abstact class in c#
 

C++ Inheritance Class Derivation Explained

  • 1. Inheritance or (class derivation) in C++ Inheritance is an idea from semantic networks in AI: e.g., robin ISA bird (draw) • a class inherits attributes from a superclass: e.g., robin inherits haspart wings from bird • Inheritance can thus be a way to model subtype relationships • e.g., a popUpMenu ISA Menu: • Inheritance becomes a way to get more code reuse: • e.g., popUpMenu inherits routines such as choosing options from Menu • Inheritance becomes a way to extend an existing class slightly: • Or, in handout, vecRange ISA vector plus lower & upper bounds & range checking • e.g., vecRange allows v(-2) if lowerbound of v is -2 or less In C++, inheritance is called class derivation and looks like this: class vecRange : public vector { int lwb, upb; //lower and upper bounds public: vecRange(int,int); //a constructor for vecRange class int& operator[] (int); //overloading array access operator } • vecRange is a derived class, vector is a base class • Derivation assumes that base class, vector, already exists! • vector's data allocates an int array of size sz • vector's public member functions include assignment, plus: int& vector::operator[](int i) { return *(v+i); } • vecRange will reuse as much of vector's code as possible • vecRange can also add new code, e.g.: overloaded operator[]: • vecRange's operator[] is overloading, and calling vector's operator[] Inheritance implies more ways to control access to class members • public keyword in derivation makes base class's members accessible to clients of vecRange • contrast with public: (with colon) which makes derived class's members accessible • private base-class prevents clients of derived class from accessing base class members • When might this come in handy? Suppose we wanted to derive Stack from vector? • Shouldn't Stack prevent its clients from having array-like access? So: Stack : private vector { //... }; --hides operator[], etc. from Stack's clients • C++ idiom: use private class derivation (or composition) for implementation reuse • Use public class derivation for subtype relations, e.g., vecRange : public vector { //... }; Suppose we want to provide access to subtypes but not world at large? • e.g., suppose vecRange wants to access a data member of its base class, v or sz? • since these are declared private in vector, they are inaccessible, even to derived classes! 1
  • 2. • enter another keyword: protected: in lieu of public: and private:, in class declaration • means that derived classes, such as vecRange, have access, but clients of class still don't 2
  • 3. /*----------------------- atm_oop.h: ATM machine ------------------*/ #include <iostream.h> #include "Lstring.h" //Account generalizes checking, savings, etc. class Account { public: int getPIN() const; //extract PIN void setPIN(int PIN); //insert PIN //PIN must have four digits float getBalance() const; //extract balance void setBalance(float); //insert balance //balance must be non-negative float addToDeposits(float); //today's deposits float getDeposits(); //extract deposits float subFromBalance(float); //withdraw from balance bool sufficientBalance(float); //can cover amount? const Lstring& getType(); //extract accountType void setType(Lstring); //insert accountType private: //note: hiding data, even from derived classes int PIN; //Personal Identification Number float balance; //not including today's deposits float deposits; //today's deposits protected: //accessible to derived classes but not clients Lstring accountType; //"checking", "savings"... Account(); //default constructor called by derived classes }; //For ATM, Checking and Savings add very little to Account class Checking : public Account { public: Checking(int PIN,float balance); Checking(); //default constructor }; //class Savings : public Account { ... }, similarly /*-------------------- excerpts from atm_oop.cpp ------------------*/ int Account :: getPIN() const { return PIN; } //extract PIN void Account :: setPIN(int pin) //insert PIN { assert(pin >= 1000 && pin <= 9999); //PIN must be 4 digits PIN = pin; } //getBalance() and setBalance are similar float Account :: subFromBalance(float withdraw) { assert(balance > withdraw); balance = balance - withdraw; } bool Account :: sufficientBalance(float amount) //cover subtraction? { return (balance >= amount); } //Constructor is protected; only call derived class constructors Account :: Account () //default constructor { deposits = 0; } //today's balance start off zero //Checking and Savings add very little to Account //... constructors just add Lstring accountType Checking :: Checking(int PIN,float balance) { setPIN(PIN); setBalance(balance); setType("checking"); 3
  • 4. } Checking :: Checking() {} //default 4
  • 5. Discussion of ATM example excerpts: • base class, Account, captures the commonality between Checking and Savings How does this commonality set up further extensions of the ATM system? (possibly other) types of bank accounts • All the new derived classes need to do is set up constructors which can in turn invoke functions like setType() and setBalance() of Account. • Base class Transaction (not shown, but available in atm_oop.h) captures the common features of derived classes Deposit and Withdrawal, all three of which are active clients of Account. • Note that the constructor for Account is protected: • so that clients cannot directly construct instances of Account, but rather just derived classes, such as Checking. Discussion of the implementation of some of the members of the Account classes: • What do the assertions accomplish? (protect the meaning of Account data) One requires that a given PIN have four digits, another (not shown) makes sure that a starting balance is non-negative, etc. While members of Account enforce these constraints, the responsibility for observing them belongs to clients of these functions, elsewhere in the ATM system. • These clients (such as those in the Transaction hierarchy) must not pass the buck to human clientsCwho aren=t interested in seeing the assertion failure error messages! What=s the difference between the if test in sufficientBalance() and the assertion in subFromBalance()? A client such as Withdrawal should test sufficientBalance()Cand display a firm but friendly message to the userCbefore attempting subFromBalance(). • The constructors in this little hierarchy are also interesting. The base class, Account, just initializes one data member, deposits, to zero. Since this constructor is protected, it can safely assume that derived class constructor will properly initialize the remaining data. • Checking has two constructors (Savings also has two, not shown, nearly the same.) The first constructor takes two arguments & initializes most of the members of its base class. Function setType() takes an Lstring which distinguishes different subtypes of Account ( useful for printing messages to the user). What about the second constructor, which doesn=t appear to do anything? The compiler needs a default constructor (with no parameters) in order to instantiate objects of a class. The compiler is quite willing to create a default constructor automatically (a facility which a few other simple classes in the ATM system take advantage of), but not if a class already has defined another constructor. So Checking needs an explicit default constructor, which gets called to set up the members of this class (mostly by invoking the constructor for the base class, Account) before executing the body of its two-parameter constructor. As you can see, the behavior of C++ code can be subtle! 5
  • 6. Suppose we derived another class from Stack, say, Staque • Would Staque have access to members of vector? Take a guess... • No: because private derivation means private to all except the immediately derived class • To anticipate this possibility, there is an intermediate access level of derived class access Stack : protected vector {//...}; • Now Staque, derived from Stack, can also access vector's members • Suppose Stack has a private member, top, which Staque should see, but not any clients In Stack, instead of private:, use protected: Lots and lots of access optionsCwhich designers must anticipate! Here's another option: suppose you want to let clients of Stack use vector's size() function: public: int size; //function size from base class is hereby visible to clients Dynamic binding in C++ Another key idea of object-oriented programming is dynamic binding • In fact, some say OOP = ADT + inheritance + dynamic binding • defer binding of a name to a type until runtime • another name for this capability is runtime polymorphism: a different function can mean different things at runtime Handout: Shape is an abstract class: has center, color and some routines • Shape declares draw() and move(Point) as virtual • This keyword tells C++ to routines support dynamic binding • meaning of these functions can vary at run-time • can bind draw() to any subclass that overloads it, e.g. Circle • Shape supplies a default definition for move(Point) • derived classes can overload this function, but don't have to • Shape also defines draw() as virtual draw()=0; --denotes a pure virtual function • derived classes must (ultimately) define a pure virtual function! • a class that includes a pure virtual function is an abstract class • an abstract class may not have a constructor (no instances of this class) • If you can't create an instance of an abstract class, what is it good for? • Abstraction, of course: generalizing about effective classes • Besides, you can assign an instance of a derived class to an abstract class • Triangle and Circle are derived from Shape • both inherit center, color data members, and where function • but both overload draw() routines: why? • What does dynamic binding buy us? More flexibility and more extensibility 6
  • 7. Suppose we wanted to have a heterogeneous vector? • e.g., suppose we wanted a vector of Shapes: Circles, Squares, etc. Shape* shapes[10]; --Compiler can allocate pointers at shapes • next two lines create a Circle and a Triangle and put them in shapes • then we loop through the array • What does shapes[0]->draw() do? What about shapes[1]->draw()? • If we didn't have dynamic binding, how could distinguish between shapes? • add a member to Shape identifying its type, say, shapeType • let each derived class's constructor intialize shapeType • add a switch statement distinguishing on shapeType: switch (shapes[i]->shapeType) { case Triangle: shapes[i]->drawTriangle(); case Circle: shape[i]->drawCircle(); //... } • What's the drawback of this switch technique? • you'll need switch statements wherever you need to distinguish subclasses • harder to extend, if you want to add a new derived class to Shapes hierarchy then you'll have to modify all these switch statements! Note: if you want dynamic binding, then you must specify the modifier, virtual! • Non-virtual functions are the default • Virtual functions have a small amount of runtime overhead computing offset to function in a table (called the Vtbl) at runtime • C programmers can be happy: OOP won't cost you anything unless you want it! • Contrast Eiffel, Smalltalk and Objective-C, for which dynamic binding is the default • Tradeoff between efficiency of C++ vs. runtime checking (and flexibility) of smalltalk or Objective-C • Why might C++ approach get in the way of extensibilty (Open-Closed Principle)? How do you know whether or how someone might want to extend your class? Design for reusability has to anticipate this possibility by making functions virtual Virtual destructors Suppose some of the classes in the Shape hierarchy had members pointing into heap So at least some these classes need their own destructors Now, suppose I want to clean up the objects I assigned to the array, shapes? Does anyone see a problem here? We'd rather not have to figure out which destructor to call--another switch statement! Looks like a job for a virtual destructor, e.g., in class Shape: virtual ~Shape() {} Then, when we run the Shape destructor, e.g.: for (int i=0; i < 10; i++) delete *shapes[i]; Now the runtime system automatically runs the right destructor! C++ idiom: if there any virtual functions in a base class, define a virtual destructor, too 7
  • 8. Multiple inheritance Single inheritance restricts class derivation to a hierarchy (tree) Smalltalk and Objective-C only support single inheritance (though there are work- arounds) But sometimes the world doesn't map into a neat heiarchy e.g., lions are carnivores, and lions are zoo animals But are all carnivores zoo animals? Or are all zoo animals carnivores? C++ (starting with 2.0) introduces the possibility of deriving from more than one base class class ZooAnimal {//...}; class Carnivore {//...}; class Herbivore {//...}; class Lion: public ZooAnimal, protected Carnivore {}; • derivation can specify a list of base classes • an instance of Lion inherits features from both ZooAnimal and Carnivore Very nice, but multiple inheritance can also complicate things! Any idea why? Name collisions--what if two parent classes have a member (feature) with the same name? Suppose two different base classes use the same name: e.g., suppose both ZooAnimal & Carnivore include a member function, locate() Using the name is ambiguous and results in a compile time error Disambiguate by using the class scope operator: Lion::locate() //Encapsulate & invokes both members { ZooAnimal::locate(); Carnivore::locate(); } Suppose a class can derive from the same base class in multiple ways? class Panda: public Bear,public Bear; //illegal--unresolvable ambiguity! But zoologlists debate about whether Panda properly belongs to Bear or Racoon families: class Panda: public Bear,public Racoon; //both derive from ZooAnimal ZooAnimal / Bear Racoon / Panda Panda Question: does class Panda get one representation of base class ZooAnimal, or two? By default, C++ generates two ZooAnimal base class parts for a Panda, e.g.: --------------- Here's how a Panda gets built: ZooAnimal part runs ZooAnimal() constructor for Bear() - - - - - - - - Bear Part runs Bear() constructor --------------- ZooAnimal part runs ZooAnimal() constructor for Racoon() - - - - - - - - Racoon part runs Racoon() constructor --------------- Panda part runs Panda() constructor--derived class is last 8
  • 9. --------------- Suppose ZooAnimal has a member, e.g., locate()--how do we invoke it from Panda? Once more, use class scope operator, e.g.: Panda::locate() { return ( (isA() == BEAR)) //isA is home-brewed RTTI ? Bear::locate : Racoon::locate() ) ; } //Intermediate base class disambiguates which ZooAnimal member to use Suppose we want don't want duplicate, ambiguous base classes? Then declare virtual base classes: class Bear: public virtual ZooAnimal {//...}; class Racoon: virtual public ZooAnimal {//...}; class Panda: public Bear,private Racoon; //both derive from ZooAnimal Panda p; p.locate(); //p has just one ZooAnimal; invokes unique ZooAnimal::locate() Note: shared virtual base class uses most accessible level of protection 9
  • 10. --------------- Suppose ZooAnimal has a member, e.g., locate()--how do we invoke it from Panda? Once more, use class scope operator, e.g.: Panda::locate() { return ( (isA() == BEAR)) //isA is home-brewed RTTI ? Bear::locate : Racoon::locate() ) ; } //Intermediate base class disambiguates which ZooAnimal member to use Suppose we want don't want duplicate, ambiguous base classes? Then declare virtual base classes: class Bear: public virtual ZooAnimal {//...}; class Racoon: virtual public ZooAnimal {//...}; class Panda: public Bear,private Racoon; //both derive from ZooAnimal Panda p; p.locate(); //p has just one ZooAnimal; invokes unique ZooAnimal::locate() Note: shared virtual base class uses most accessible level of protection 9