Inheritance in C++
Inheritance in C++
Lesson #6
Note: CIS 601 notes were originally developed by H. Zhu for NJIT DL Program. The notes were subsequently revised by M. Deek.
1
Content
Base and Derived Classes
Single Inheritance
Declaration of derived classes
Order of Constructor and Destructor Execution
Inherited member accessibility
Multiple Inheritance
Virtual Base Classes
2
Base and Derived Classes
A base class is a previously defined
class that is used to define new
classes
3
Single Inheritance
Implement an “is-a” relationship
The derived class only has one base
class.
4
Example 1:
Student
• name
• id
• major
Undergraduate Graduate
• year • advisor
• minor • thesis
• etc. • research
• etc...
5
Example 2:
Publication:
• publisher
• date
Magazine: Book:
• # of issues per year • ISBN
• circulation • author
6
Example:
#include “FString.h" Publication
class Publication {
public:
void SetPublisher( const FString & p )
{publisher.Assign(p);};
void SetDate( unsigned long dt )
{date = dt;};
FString GetPublisher(){return publisher;};
unsigned long GetDate(){return date;};
private:
FString publisher;
unsigned long date;
};
7
Publication
class Magazine :public Publication {
public:
void SetIssuesPerYear( unsigned n )
{issuesPerYear=n;};
void SetCirculation( unsigned long n )
{ circulation=n;};
unsigned GetIssuesPerYear(){return
issuesPerYear;};
unsigned long GetCirculation(){return circulation;};
private:
unsigned issuesPerYear;
unsigned long circulation;
};
8
class Book :public Publication {
Publication
public:
void SetISBN( const FString & s )
{ISBN.Assign(s);};
void SetAuthor( const FString & s )
{author.Assign(s);};
FString GetISBN()
{return ISBN;};
FString GetAuthor()
{return author;};
private:
FString ISBN;
FString author;
9 };
int main()
{Book B;
Publication
B.SetPublisher( "Prentice Hall" );
B.SetDate( 970101L );
B.SetISBN( "0-02-359852-2" );
B.SetAuthor( "Irvine, Kip" );
cout << B.GetPublisher()<<endl
<<B.GetDate()<<endl
<<B.GetISBN().CString()<<endl
<<B.GetAuthor().CString()<<endl;
Magazine M;
M.SetIssuesPerYear( 12 );
M.SetCirculation( 500000L );
cout << M.GetIssuesPerYear()<<endl
<<M.GetCirculation()<<endl;
return 0;
}//ex6pub(Fstring.h, fstring.cpp, ex6pub.cpp)
10
Different Views of an
Employee
Full-time or part-time
Permanent or Temporary
How do you define its base class?
How td you define derived classes
based on this base class?
11
Declaring Derived Classes
Class class_name: access_specifieropt
or base_class { Member_list
}
access_specifier ::= public|protected|
private(default)
Equivalent to :
Subclass ::=<Id, SupeId, Ds, Ops, Intfc>
12
3D Point
class Point {
public:
Point();
Point( int xv, int yv );
void SetX( int xv );
void SetY( int yv );
private:
int x;
int y;
};
13
3D Point
class Point3D :public Point {
public:
Point3D();
Point3D( int xv, int yv, int zv );
void SetZ( int zv );
private:
int z;
};
14
3D Point
Point3D::Point3D( int xv, int yv, int zv )
{ SetX( xv );
SetY( yv );
int main()
{
SetZ( zv ); Point3D P;
} P.SetX( 100 );
P.SetY( 200 );
P.SetZ( 300 );
return 0;
}
15
Order of Constructor and
Destructor Execution
16
Class Employee{
Public: Example
Employee();
//…
};
Class SalariedEmployee:public Employee{
Public:
SalariedEmployee();
//…
};
Class ManagementEmployee:public SalariedEmployee{
Public:
ManagementEmployee();
//…
};
ManagementEmployee M;
17
Example
2 Coordinate
Point
Shape 1
1 Point3D
Sphere
18
#include <iostream.h>
class Coordinate { Example
public:
Coordinate() { cout << "Coordinate,"; }
~Coordinate() { cout << “~Coordinate,"; }
};
class Point {
public:
Point() { cout << "Point,"; }
~Point() { cout << “~Point,"; }
private:
Coordinate x;
Coordinate y;
};
19
Example
class Point3D :public Point {
public:
Point3D() { cout << "Point3D,"; }
~Point3D() { cout << “~Point3D,"; }
private:
Coordinate z;
};
class Shape {
public:
Shape() { cout << "Shape,"; }
~Shape() { cout << “~Shape,"; }
};
20
class Sphere :public Shape {
public:
Sphere() { cout << "Sphere"; }
~Sphere() { cout << "Sphere"; }
private:
Point3D center;
unsigned radius;
};
int main()
{ Sphere S; Example
return 0;
} //See Ex6-1.cpp
21
22
Overriding
A function in the derived class with
the same function name will override
the function’s variables in the base
class.
You can still retrieve the overridden
functions variables by using the scope
resolution operator ”::”.
23
#include <iostream.h>
#include <stdlib.h> Overriding
class A
{ int i; void main()
public: { B b;
A(){i = 5;};
int x;
int get(){return i;};
}; cout << b.get()<<endl;
class B: public A cout << b.A::get()<<endl;
{ int i; cout << sizeof(x)<<endl;
public:
cout << sizeof(b)<<endl;
B(){i = 10;};
int get(){return i;}; }//ex7overriding.cpp
};
24
Types of Class Members
private
protected
public
25
Types of Class Members
Accessible to
Public
derived
Protected classes and the
instances
Private
Accessible
to derived
? not classes
accessible only
Derived
26
Class
Types of Inheritance
public
private
protected
27
Public Inheritance
Public and protected members of the
base class become respectively
public and protected members of the
derived class.
28
Public
Protected
Private
public
Public
Protected
Private
Class
Functions(instances)
29
#include <iostream.h> Example
#include <assert.h>
class Item {
Item * ptr;
int data;
public:
Item(){data = 0; ptr = NULL;};
Item(int i){data = i; ptr = NULL;
cout <<"Item::Item"<<i <<endl;
};
30
Example
void setItem(int i){data = i;
cout <<"Item::setItem"<<i <<endl;
};
void setPtr(Item * i){ptr = i;
cout <<"Item::setPtr"<<endl;
};
int getData(){return data;};
Item * getPtr(){return ptr;};
};
31
class List {
Item * head, *first, *last;
Example
public:
List(){ head = NULL;
first = head;
last = head; }
Item * RemoveLast();
Item * RemoveFirst();
void PutFirst( Item * I );
void PutLast( Item * I );
protected:
int IsEmpty() const
{return (head==NULL);};
};
32
Item * List::RemoveFirst()
{ Item * temp; Example
temp = first;
first = first -> getPtr();
cout <<"List:: RemoveFirst()"<<endl;
return temp;
};
Item * List::RemoveLast()
{ Item * temp;
temp = last;
last = last -> getPtr();
cout <<"List:: RemoveLast()"<<endl;
return temp;
};
33
Example
void List::PutFirst(Item * I)
{ I->setPtr(first);
first = I;
cout <<"List::PutFirst"<<I->getData() <<endl;
};
void List::PutLast(Item * I)
{ I->setPtr(last);
first = I;
};
34
class Stack :public List {
public:
Example
void Push( Item * I );
Item * Pop();
};
void Stack::Push( Item * I )
{PutFirst( I );
cout <<"Stack::Push"<<I->getData() <<endl;
}
Item * Stack::Pop()
{cout <<"Stack::Pop()"<<endl;
return RemoveFirst();
}
35
Example
int main()
{Item anItem(50), *p;
Stack aStack;
aStack.Push( &anItem );
p = aStack.Pop();
cout <<"aStack.Pop"<< p->getData()<<endl<<endl;
anItem.setItem(100);
aStack.Push( &anItem );
p = aStack.RemoveFirst();
cout <<"aStack.RemoveFirst"<< p-
>getData()<<endl<<endl;
return 0;
36 }//ex6-2.cpp
37
38
Private Inheritance
Public and protected members of the
base class become private members
of the derived class.
39
Public
Protected
Private
private
Public
Protected
Private
Function(instances) Class
40
class Queue :private List {
public:
Example
void Enqueue( Item * I );
Item * Serve();
};
void Queue::Enqueue( Item * I )
{ List::PutFirst( I );
cout <<"Queue::Enqueue"<<I->getData() <<endl;
}
Item * Queue::Serve()
{cout <<"Queue::Serve"<<endl;
return List::RemoveFirst();
}
41
int main()
{Item anItem(50), *p;
Queue aQueue;
Example
anItem.setItem(60);
aQueue.Enqueue(&anItem);
p = aQueue.Serve();
cout <<"aQueue.Serve"<< p->getData()<<endl<<endl;
anItem.setItem(600);
aQueue.Enqueue(&anItem);
p =aQueue.RemoveFirst(); //Unaccessible
//cout <<"aQueue.RemoveFirst"<< p->getData()<<endl;
return 0;
}//ex6-3.cpp
42
43
Protected Inheritance
Public and protected members of the
base class become protected
members of the derived class.
44
Public
Protected
Private
protected
Public
Protected
Private
Function(instances) Class
45
class Stack1 :protected List { Example
public:
void Push( Item * I );
Item * Pop();
};
void Stack1::Push( Item * I )
{PutFirst( I );
cout <<"Stack1::Push"<<I->getData() <<endl;
}
Item * Stack1::Pop()
{cout <<"Stack1::Pop()"<<endl;
return RemoveFirst();
}
46
int main()
Example
{Item anItem(50), *p;
Stack1 aStack1;
aStack1.Push( &anItem );
p = aStack1.Pop();
cout <<"aStack1.Pop"<< p->getData()<<endl<<endl;
anItem.setItem(100);
aStack1.Push( &anItem );
p = aStack1.RemoveFirst();//Unaccessible!
cout <<"aStack1.RemoveFirst"<< p->getData()
<<endl<<endl;
return 0;
}
47
48
The accessibility of inherited
members in a derived class
Protected X X
Private
49
The accessibility of inherited
members for an instance
Protected
Private
50
Constructor- Initializers
Point3D::Point3D(param-list): ctor-
initializer
{// function body
}
ctor-initializer is actually used to
transfer the parameters to the
constructors of the base-class
51
#include <iostream.h>
Publication
#include <string.h>
class Date
{
public:
Date( int mo, int dy, int yr )
{
month = mo; day = dy; year = yr;
cout << "Date constructor\n";
}
// Ex6pub2.cpp
52
Date( Date & D )
Publication
{
month = D.month; day = D.day; year = D.year;
cout << "Date copy constructor\n";
}
~Date() { cout << "Date destructor\n"; }
private:
int year;
int month;
int day;
};
53
class Publication
{
Publication
public:
Publication( char * publshr, Date & aDate )
: pubDate( aDate )
{
strcpy( publisher, publshr);
cout << "Publication constructor\n";
}
~Publication()
{ cout << "Publication destructor\n"; }
private:
char publisher[30];
Date pubDate;
54 };
class Magazine :public Publication Publication
{public:
Magazine( char * publshr, Date & aDate,
int issues ): Publication( publshr, aDate )
{issPYear = issues;
cout << "Magazine constructor\n";
}
~Magazine() { "Magazine destructor\n"; }
private:
int issPYear; // issues per year
};
int main()
{ Magazine aMag( "Zipp", Date(10, 1, 95), 12 );
return 0;
55 }
56
Why use the
constructor-initializer?
Without it, the default constructor for
the base class would be called, which
would then have to be followed by
calls to access functions to set
specific data members.
A constructor initailizer is therefore
more efficient.
57
Constructors in Derived
Classes
When an object of a derived class is c
reated, the constructor of the object m
ust first explicitly call the constructor o
f the base class.
This is the same as constructor- initial
izer.
58
Destructor Function
Destructors are called implicitly
starting with the last derived class and
moving in the direction of the base
class.
59
Compatibility Between
Base and Derived Classes
60
Nested Class Scope
A public or protected base class
member that is hidden from the derived
class can be accessed using the scope
resolution operator ” ::”
For example: base-class::member
The “that” of base class can not access
the members of its derived classes.
61
Class Parent {
public:
Example
void Print() const;
//…
}
class Child: public Parent {
public:
void Print() const{
Parent::print();// scope resolution !!!
cout <<age<<‘\n’
<<school<<‘\n’;
}
private;
int age;
Fstring school;
}
62
Error
Void Parent::Print() {
cout<<name <<‘\n’
<<Child::age <<‘\n’;
//base can not access that of derived
}
63
Implicit Conversion of Derived
Pointers to Base Pointers
A base type pointer can point to either
a base object or a derived object.
Point3D center;// Point3D is derived from Point
Point * p = ¢er;
64
class FString { }; Example
class Student {
public: //...
private:
long id;
};
class GraduateStudent :public Student {
public: //...
private:
FString thesisTitle;
};
65
Example
void CalcTuition( Student & sp )
{ /* sp is a Student or a derived object */}
void RecordThesis( GraduateStudent * p )
{ /*... */ }
int main()
{Student * sp;
GraduateStudent * gp; //...
sp = gp; //...
RecordThesis( (GraduateStudent *) sp );
return 0;
}
66
Casting Base Pointers to
Derived Pointers
A base pointer can not be implicitly
converted to a derived pointer.
This conversion is risky, because the
derived object can contain more than
the base object.
67
Example
void DoSomething(const GraduateStudent *
GS)
{ cout << GS->GetThesisTitle();}
68
class Item {/* …*/} Example
class Student: public Item{/* …*/}
class Collection {
public:
void Append (const Item * ip);
Item * Get() const; }
const unsigned Count = 10;
Collection studentList;
Student * p;
for (int i=0; i<Count; i++ )
{p = new Student;
studentList.Append(p);}
p = (student*) studentList.Get();//explicit cast
69
Attention
Forcing class users to use explicit casting
often leads poor code.
class studentCollection:public Collection{
public:
student * Get() const
{ return (student *) Collection::Get(); }
//…
}
studentCollection studentList;
student *p;
//…
p = studentList.Get(); // no cast required
70
Multiple Inheritance
employee
Student
salaried
GraduateAssistant
71
#include <iostream.h>
#include "fstring.h"
typedef unsigned long ulong; Example
class Student {
public:
unsigned GetAge() const;
ulong GetId() const;
unsigned GetMajor() const;
void SetAge( unsigned n );
void SetId( ulong n );
void SetMajor( unsigned n );
private:
ulong id;
unsigned majorCode;
unsigned degreeCode;
float gpa;
unsigned age;
72
};
class Employee {
public: Example
unsigned GetAge() const;
const FString & GetBenefits() const;
unsigned GetExemptions() const;
void SetAge( unsigned n );
void SetBenefits( const FString & benef );
void SetExemptions( unsigned n );
private:
unsigned age;
unsigned exemptions;
FString benefits;
};
73
class Salaried :public Employee {
public:
Example
float GetSalary() const;
void SetSalary( float s );
private:
float salary;
};
class GradAssistant :public Student, public Salarie
d{
public:
void Display() const;
};
74
void GradAssistant::Display() const
{ cout << GetId() << ','
<< GetMajor() << ','
Example
<< GetSalary() << ','
<< GetExemptions() << endl;
}
int main()
{ GradAssistant GA;
GA.SetId(12345);
// GA.SetAge(22); // error: ambiguous
GA.Student::SetAge(22); // ok - specific
GA.SetMajor(108);
GA.SetExemptions(2);
GA.SetSalary(10000);
GA.Display();
return 0;
}//ex6mulin.cpp
75
76
77
78
Example
Question:
If we want to set a GradAssistant ‘s
age by calling SetAge(), which SetA
ge() should we use use?
1. Direct solution: Student::SetAge() or S
alaried::SetAge().
2. Abstract(Virtual) base classes
79
Virtual base classes
Person
employee
Student
salaried
Graduate Assistant
80
#include <iostream.h>
#include "fstring.h"
Example
typedef unsigned long ulong;
class Person {
public:
unsigned GetAge() const;
const FString & GetSocSecNum() const;
void SetAge( unsigned n );
void SetSocSecNum( const FString & ssn );
private:
unsigned age;
FString socSecNum;
};
81
Example
class Student :public virtual Person {
public:
unsigned GetMajor() const;
void SetMajor( unsigned n );
private:
unsigned majorCode;
unsigned degreeCode;
float gpa;
};
82
Example
class Employee :public virtual Person {
public:
const FString & GetBenefits() const;
unsigned GetExemptions() const;
void SetBenefits( const FString & benef );
void SetExemptions( unsigned n );
private:
unsigned exemptions;
FString benefits;
};
83
Example
class Salaried :public Employee {
public:
float GetSalary() const;
void SetSalary( float s );
private:
float salary;
};
class GradAssistant :public Student, public Sa
laried {
public:
void Display() const;
};
84
Example
void GradAssistant::Display() const
{ cout << GetSocSecNum() << ','
<< GetAge() << ',‘
// ambiguous if not virtual
}
int main()
{ GradAssistant GA;
return 0;
}
85
86
Virtual Base Classes
The function calls in GradAssistant::Displ
ay() are ambiguous unless Person is inheri
ted as a virtual base class.
Adding “virtual” lets the compiler decid
e which function and which variable sh
ould be accessed.
87
Virtual Base Classes
Person(22)
Employee(22)
Student(8)
Salaried(4)
GraduateAssistant(0)
aGA(78)
88
Virtual Base Classes(end)
Person(22)
virtual virtual
Employee(22)
Student(8)
Salaried(4)
GraduateAssistant(0)
aGA(56)
89
Readings
Readings
Chapter 6 Sections 6.1.3 – 6.5
90