Download Inheritance

Document related concepts
no text concepts found
Transcript
Chapter 7
INHERITANCE
1
Outlines
• 7.1 Fundamentals of Inheritance
• 7.2 The protected Access Specifier
• 7.3 Constructing and Destroying Derived
Classes
• 7.4 Multiple Inheritance
• 7.4.1 Direct Multiple Inheritance
• 7.4.2 Indirect Multiple Inheritance
• 7.5 Dominating and Overriding Base Class
Members
2
Introduction
• Code reusability is a very important
programming concept, and C++ facilitates
this concept more efficiently than C.
• Inheritance is one of the most powerful
OOP tools in the implementation of code
reusability in C++.
• When using inheritance, a new class can
be created by establishing parent-child
relationships with existing classes.
3
7.1 FUNDAMENTALS OF
INHERITANCE
• Inheritance is a relationship between classes in
which one class inherits the properties
(attributes and behaviors) of another class.
• Implementing inheritance promotes code
reusability because new classes are created
from existing classes.
• Inheritance is also called derivation or an is-a
relationship.
• It enables a hierarchy of classes to be designed.
• The hierarchy begins with the most general
class and moves to more specific classes.
4
•
By implementing inheritance, data members and
member functions from one class (higher in hierarchy)
can become properties (members) of another class
(lower in hierarchy) without coding them explicitly within
this class.
• A class that is inherited (higher in hierarchy) is called a
base class or a parent class. A class (lower in
hierarchy) that inherits properties of another class (base
class) is called a derived class or child class.
5
Inheritance hierarchy
6
• The base class defines all properties that
can be inherited by any derived class, as
well as some non-inheritable private
properties of its own.
• Inheritance continues with the definition of
a derived class that contains the
properties inherited from the base class
and some other properties that are specific
to the derived class.
7
Formulation
class
derived_class_name:access_specifier
base-class-name
{
//specific properties of the derived-class
}
8
class Amplifier { //base class
public:
float gain;
//gain
float involt, outvolt;
//input and
output voltag
void setGain();
//Sets gain
void setInvolt(); //Sets input voltagevoid get0utvolt(); //Computes and
displays output
9
Type of inheritance
• Single inheritance : a class is derived from only one
base class (a child class has only one parent class).
– A parent class, however, can have many child classes.
10
• Multiple inheritance, a class can have
more than one parent class.
• Multiple inheritance is discussed in
Section 7.4.
11
• access specifier that precedes a base class
name defines the status of the members
inherited from the base class within the derived
class.
• The private access specifier means that all
members inherited from the base class will be
private in the derived class.
• The access specifier is public, all inherited
members will have the same status in the
derived class as the status these members have
in the base class.
12
Default
• When inheriting from a base class, the
default access is private. It can therefore
be omitted in the header of a derived class
definition as follows:
class OPAMP : Amplifier {
//members specific to OPAMP
};
13
• The members that are inherited from the
Amp1ifier class are private to the 0PAMP
class in this example.
• Any class that is derived from 0PAMP
cannot inherit these members.
14
• The following data members and functions
cannot be inherited from a base class:
– private members (private data members and
private member functions)
– Constructor and destructor functions
– friend functions
– static functions
– Operator functions that overload the
assignment operator
15
7.2 THE protected ACCESS
SPECIFIER
• The protected access specifier is used only when
implementing inheritance. To enable a derived class to
access members of a base class while keeping these
members hidden from the rest of the program.
• Members of a base class that are specified as protected
can be accessed directly by
– Any non static member function of a base class
– Any friend function of a base class
– Any non static member function of a class derived from the base
class
– Any friend function of a class derived from the base class
16
class Amplifier (
//base class
private:
float involt, outvolt; //input and output voltage
protected:
float gain; //gain
public:
..
void setGain();
//Sets gain
void setInvolt();
//Sets input voltage
float getOutvolt();
//Computes and displays output voltage
class OPAMP : public Amplifier (
//derived class
private:
float rin;
//input resistor
float rout; //feedback resistor
public:
void setResist();
//Sets resistors
float getGain();
//Computes and returns gain
17
• When defining a derived class, protected can
also be used to specify a type of inheritance.
The type of inheritance is specified by the
access specifier (private,protected, or public),
which precedes a base class name in the
header of a derived class.
• All public and protected members inherited from
the base class with the protected access
specifier will be protected in the derived class.
Table 7.2 shows the three types of inheritance
and how each type affects the status of inherited
members within a derived class.
18
19
20
7.3 CONSTRUCTING AND DESTROYING
DERIVED CLASSES
• Every base and derived class in an inheritance hierarchy
should have its own constructor and destructor functions.
• Constructors and destructors cannot be inherited.
• When instantiating an object of a derived class,
constructors of all of its parent classes are executed
prior to the derived class constructor.
• This is understandable because when creating a child,
all of its parents have to be created before the child can
be created. The constructor functions, therefore, are
executed in the order of derivation within the inheritance
hierarchy.
21
22
Parameters list
• If a base class constructor has arguments, these
arguments also have to be added to the argument list of
any class derived from this base class.
• When instantiating an object of the derived class, all of
the arguments required by the base constructor and
derived constructor are first passed to the derived
constructor. The derived constructor then passes
appropriate arguments along to the base class
constructor.
derived_class(arg_list1):base class(arg_list2)
{
//body of derived class constructor
}
23
24
//PROG7_1: Program demonstrates the mechanisms of constructing
//
and destroying objects of derived classes.
#include <iostream>
#include <iomanip>
using namespace std;
class Amplifier {
//base class
float involt;
//input voltage
float outvolt; //output voltage
protected:
float gain;
public:
Amplifier(float=0, float=1);
//constructor
~Amplifier(){cout<<"Destroying amplifier!"<<endl;} //destructor
void setInvolt(float inv) { involt=inv; }
float getOutvolt(){outvolt=involt*gain; return outvolt;}
};
Amplifier::Amplifier(float inv, float g)
//base constructor
{ cout<<"Constructing amplifier!"<<endl;
involt=inv; gain=g;
outvolt=involt*gain;
}
25
class OPAMP_NI:public Amplifier {
//derived class
float rin;
//input resistor
float rf;
//feedback resistor
public:
OPAMP_NI(float=0, float=1, float=0, float=0);
//constructor
~OPAMP_NI(){cout<<"\nDestroying OPAMP!"<<endl;}
//destructor
void setRes(float r1, float r2){rin=r1; rf=r2;}
float getGain(){gain=1+rf/rin; return gain;}
};
OPAMP_NI::OPAMP_NI(float v, float a, float r1, float
r2):Amplifier(v, a)
{
//derived constructor
cout<<"Constructing OPAMP!"<<endl;
rin=r1; rf=r2;
}
26
int main()
{
OPAMP_NI amp1;
//derived class's object
float r1, r2, volt;
cout<<"\n\tEnter input and feedback resistor => ";
cin>>r1>>r2;
amp1.setRes(r1,r2);
cout<<"\tEnter input voltage => ";
cin>>volt;
amp1.setInvolt(volt);
cout<<setiosflags(ios::fixed)<<setprecision(2);
cout<<"\n\t\tGain = "<<amp1.getGain( )<<endl;
cout<<"\t\tOutput Voltage = "<<amp1.getOutvolt()<<"
[V]\n";
return 0;
}
27
28
7.4 Multiple inheritance
• When implementing multiple inheritance, a
class can be derived directly or indirectly from
as many parent classes as necessary. There
are two types of multiple inheritance:
– Direct multiple inheritance
– Indirect multiple inheritance
29
7.4.1 DIRECT MULTIPLE
INHERITANCE
• When implementing direct multiple inheritance, a derived
class can directly inherit more than one base class.
• To define a class that directly inherits multiple base
classes, the general format is
class Derived class:access specifier Base1_class,
access specifier Base2_class, ...,
access specifier BaseN class
{
//body of derived class
};
30
31
//PROG7_2: Program demonstrates direct multiple
//inheritance.
#include <iostream>
using namespace std;
class Resistor {
//base class # 1
protected:
double res;
//resistance
public:
Resistor(double r) { res=r; }
void setRes() { cout<<"\tEnter R = "; cin>>res; }
double getRes() { return res; }
};
32
class Capacitor {
//base class # 2
protected:
double cap;
//capacitance
public:
Capacitor(double c) { cap=c; }
void setCap() { cout<<"\tEnter C = ";
cin>>cap; }
double getCap() { return cap; }
};
33
class Low_Pass:public Resistor,public Capacitor
{ //derived class
double frq_cut; //cutoff frequency
public:
Low_Pass (double, double);
//derived constructor
void setFreq() { frq_cut=1/(res*cap); }
double getFreq() { return frq_cut; }
};
Low_Pass::Low_Pass(double r, double
c):Resistor(r),Capacitor(c)
{
//derived constructor with initialization list
setFreq();
}
34
int main()
{
Low_Pass filter(1000, 0.00000047);
cout<<"Low-Pass Filter:"<<endl;
cout<<"\tR = "<<filter.getRes()<<" ohms"<<endl;
cout<<"\tC = "<<filter.getCap()<<" F"<<endl;
cout<<"\tCutoff Frequency = "<<filter.getFreq()<<" rad/s";
cout<<"\n\nAfter changing R and C:"<<endl;
filter.setRes();
filter.setCap();
filter.setFreq();
cout<<"\tCutoff Frequency = "<<filter.getFreq()<<" rad/s";
return 0;
}
35
36
37
38
7.4.2 INDIRECT MULTIPLE
INHERITANCE
• A class can indirectly
inherit members of
another class through
its base class.
• The original base
class in this case is
derived from another
base/parent class,
creating a multilevel
inheritance hierarchy.
39
//PROG7_3: Program demonstrates indirect multiple inheritance.
#include <iostream>
using namespace std;
class RC_Circuit {
//base class
protected:
double res;
//resistance
double cap;
//capacitance
public:
RC_Circuit(double r, double c) { res=r; cap=c; }
void setRes() { cout<<"\tEnter R = "; cin>>res; }
double getRes() { return res; }
void setCap() { cout<<"\tEnter C = "; cin>>cap; }
double getCap() { return cap; }
};
class Filter:public RC_Circuit {
//derived classs #1
protected:
double frq;
//frequency
public:
Filter(double r, double c, double f):RC_Circuit(r,c){frq=f;}
double getFreq() { return frq; }
};
40
class Low_Pass:public Filter {
//derived class #2
double frq_cut; //cutoff frequency
public:
Low_Pass (double, double, double);
void setCutoff() { frq_cut=1/(res*cap); }
double getCutoff() { return frq_cut; }
bool isPreserved();
};
Low_Pass::Low_Pass(double r, double c, double
f):Filter(r,c,f)
{
setCutoff();
}
bool Low_Pass::isPreserved()
{
return ((frq<=frq_cut)? true : false);
}
41
int main()
{
Low_Pass filter(1000, 0.00000047, 2500);
cout<<"Low-Pass Filter:"<<endl;
cout<<"\tR = "<<filter.getRes()<<" ohms"<<endl;
cout<<"\tC = "<<filter.getCap()<<" F"<<endl;
cout<<"\tCutoff Frequency = "<<filter.getCutoff()<<"
rad/s";
if(filter.isPreserved()) {
cout<<"\n\tFrequency = "<<filter.getFreq();
cout<<" rad/s is preserved."<<endl;
}
else {
cout<<"\n\tFrequency = "<<filter.getFreq();
cout<<" rad/s is attenuated."<<endl;
}
42
cout<<"\n\nAfter changing R and C:"<<endl;
filter.setRes();
filter.setCap();
filter.setCutoff();
cout<<"\tCutoff Frequency = "<<filter.getCutoff()<<"
rad/s";
if(filter.isPreserved()) {
cout<<"\n\tFrequency = "<<filter.getFreq();
cout<<" rad/s is preserved."<<endl;
}
else {
cout<<"\n\tFrequency = "<<filter.getFreq();
cout<<" rad/s is attenuated."<<endl;
}
return 0;
}
43
44
7.5 DOMINATING AND
OVERRIDING BASECLASS
MEMBERS
• When inheriting from a base class, some
inherited members can be overridden and the
others dominated by members of a derived class.
• In either case, members inherited from the base
class have the same name (identifier) as
members of the derived class that override or
dominate the inherited members.
• a data member of a derived class dominates a
data member inherited from a base class that
uses the same identifier.
45
//PROG7_4: Program demonstrates the principles
// of dominating and
//
overriding inherited members.
#include <iostream>
using namespace std;
class Resistor {
//base class
public:
float r;
//resistance
Resistor(float x = 0) { r=x; }
void getVal() { cout<<"R = "<<r<<endl; }
};
46
class Circuit:public Resistor
{
//derived class
public:
float r;
//resistance
double c;
//capacitance
Circuit(float x, double y):Resistor(330)
{ r=x; c=y; }
void getVal() { cout<<"R = "<<r<<" C =
"<<c<<endl; }
};
47
int main()
{
Resistor res1(470);
Circuit cir1(200, 0.0001), cir2(1000,
0.0005);
cout<<"\t\tAccessing data members:\n\n";
cout<<"res1.r = "<<res1.r<<endl;
cout<<"cir1.r = "<<cir1.r<<endl;
cout<<"cir2.r = "<<cir2.r<<endl;
cout<<"cir1.Resistor::r = “<<cir1.Resistor::r<<endl;
cout<<"cir2.Resistor::r = "<<cir2.Resistor::r<<endl;
48
Resistor res2=cir2;
cout<<"res2.r = "<<res2.r<<endl;
cout<<"\n\t\tExecuting member
functions:\n\n";
res1.getVal();
cir1.getVal();
cir1.Resistor::getVal();
cout<<"\n\t\tUsing a base class pointer:\n\n";
Resistor *rptr;
rptr=&res1;
rptr->getVal();
rptr=&cir1;
rptr->getVal();
return 0;
}
49
• The base class name followed by the scope
resolution operator (::) is used only in cases in
which it is necessary to distinguish inherited
members from the members with the same
name declared within the derived class.
50
51
• To determine which of these two functions
will be invoked when using cir1.getVa
1( )(line 32), C++ uses the following
principle: a function defined within a
derived class over rides a function with the
same signature that is inherited from a
base class.
52
53
54