·
Inheritance Allows
us to write reusable code. Inheritance
is the process by which we can create a new class (derived class) that is
created from another class known a base class.
o
An easy way of
thinking about inheritance is to think of family relationships. The base class is often called the parent
class and the derived class is called the child class.
§
If class A
derives from class B, then B is the parent of A and A is the child of B.
§
If a class A
derives from a class B which derives from class C, we say that A is a child of
B and a descendent of C. B is a parent
of A and a child of C. C is a parent of
B and an ancestor of A.
o
The derived class
will inherit member variables and functions of the base class. However, it will only have direct access to
those that are public or protected. It
will not have access to private member variables or private member functions.
o
Certain functions
are not inherited: Constructors,
Destructors, Copy Constructors, Assignment operators are all not
inherited. The must be invoked from the
derived object accordingly as shown later in this lecture.
o
The definition of
an inherited member function (from the base class) may be changed in the
derived class. This is known as member
function redefinition.
§
Function
redefining is not the same as function overloading. With function redefining, the new function
definition given in the derived class has the same number and types of
parameters (same function signature).
Overloaded functions have different number of parameters of different
types (different function signatures).
o
// Example
#include <iostream>
#include <iomanip>
using namespace std;
class Mammal
{
public:
Mammal();
Mammal(int age, int weight);
~Mammal();
void setAge(int
age);
int getAge()
const;
void setWeight(int
weight);
int getWeight()
const;
void speak() const;
private:
int _age;
int _weight;
};
Mammal::Mammal() : _age(0), _weight(0)
{
cout << "Mammal
Constructor #1 Called.\n";
}
Mammal::Mammal(int age, int
weight) : _age(age), _weight(weight)
{
cout << "Mammal
Constructor #2 Called.\n";
}
Mammal::~Mammal()
{
cout << "Mammal
Destructor Called.\n";
}
void Mammal::setAge(int age)
{
_age =
age;
}
int Mammal::getAge()
const
{
return _age;
}
void Mammal::setWeight(int weight)
{
_weight =
weight;
}
int Mammal::getWeight()
const
{
return _weight;
}
void Mammal::speak() const
{
cout << "Mammal speak()
called.\n";
}
// Class RaceDog and
implementations
class RaceDog
: public Mammal
{
public:
RaceDog();
RaceDog(int age, int weight, int wins, int losses);
~RaceDog();
void speak() const;
void displayStatistics() const;
void setWins(int
wins);
int getWins()
const;
void setLosses(int
losses);
int getLosses()
const;
private:
int _wins;
int _losses;
};
RaceDog::RaceDog() : Mammal(), _wins(0),
_losses(0)
{
cout << "RaceDog Constructor #1 Called.\n";
}
RaceDog::RaceDog(int age, int
weight, int wins, int
losses)
: Mammal(age, weight), _wins(wins), _losses(losses)
{
cout << "RaceDog Constructor #2 Called.\n";
}
RaceDog::~RaceDog()
{
cout << "RaceDog Destructor Called.\n";
}
void RaceDog::speak()
const
{
cout << "Bark!\n";
}
void RaceDog::displayStatistics()
const
{
cout << "Age = " << setw(3)
<< getAge()
<< endl;
cout << "Weight =
" << setw(3) << getWeight()
<< endl;
cout << "Wins = " << setw(3)
<< getWins()
<< endl;
cout << "Losses =
" << setw(3) << getLosses()
<< endl;
}
void RaceDog::setWins(int wins)
{
_wins =
wins;
}
int RaceDog::getWins()
const
{
return _wins;
}
void RaceDog::setLosses(int losses)
{
_losses =
losses;
}
int RaceDog::getLosses()
const
{
return _losses;
}
// Class Cat and implementations
class Cat : public Mammal
{
public:
Cat();
Cat(int age, int
weight);
~Cat();
void speak() const;
};
Cat::Cat() : Mammal()
{
cout << "Cat Constructor
#1 Called.\n";
}
Cat::Cat(int age, int
weight) : Mammal(age, weight)
{
cout << "Cat
Constructor #2 Called.\n";
}
Cat::~Cat()
{
cout << "Cat Destructor
Called.\n";
}
void Cat::speak()
const
{
cout << "Meow!\n";
}
// driver function
int main()
{
RaceDog A, B(2, 59, 4, 17);
Cat C;
// Set
the age, weight for RaceDog A
A.setAge(3);
A.setWeight(64);
// Set
wins and losses for RaceDog A
A.setWins(8);
A.setLosses(20);
cout << "The A dog says
";
A.speak();
A.displayStatistics();
cout << "The C Cat says
";
C.speak();
cout << "The B dog says
";
B.speak();
B.displayStatistics();
// Here's
how we would invoke speak from the base class()
C.Mammal::speak();
return 0;
}
// Output
Mammal Constructor #1 Called.
RaceDog Constructor #1 Called.
Mammal Constructor #2 Called.
RaceDog Constructor #2 Called.
Mammal Constructor #1 Called.
Cat Constructor #1 Called.
The A dog says Bark!
Age
= 3
Weight = 64
Wins
= 8
Losses = 20
The C Cat says Meow!
The B dog says Bark!
Age
= 2
Weight = 59
Wins
= 4
Losses = 17
Mammal speak()
called.
Cat Destructor Called.
Mammal Destructor Called.
RaceDog Destructor Called.
Mammal Destructor Called.
RaceDog Destructor Called.
Mammal Destructor Called.
o
The protected Qualifier If you use the qualifier protected, rather than private or public, before a member variable or member function of a
class, then for any class or function other than a derived class the effect is
the same as if the member variable were labeled private;
however, in a derived class, the
variable can be accessed directly by name.
o
Assignment
Operator in Derived Classes If you overload the assignment operator in the
derived class, you should also use the assignment operator from the base class.
o
Copy Constructor
in Derived Classes If you use a copy constructor in a derived class, you
should also use the copy constructor from the base class.
o
Destructors in
Derived Classes When the destructor for the derived class is invoked, it invokes
the destructor of the derived class and then automatically invokes the
destructor of the base class. There is
no need for the explicit writing of a call to the base class destructor. It always happens automatically, which is why
the order of destructor calls is the reverse order in which the constructors
are called.
o
Review
Displays: 14.8, 14.9 14.10, 14.11, 14.12
o
Is-A
Relationship An easy way to think of making a complex class is to think of
the class relationship. If there is an
Is-A relationship (for example, a Cat is a Mammal), then Cat should inherit
from Mammal.
o
Has-A
Relationship If there is a Has-A relationship (for example, an automobile
has an engine), then the engine class should be made an element of the
automobile class.
§
Now think of
this: A race car is an automobile. Therefore, RaceCar
should inherit from Automobile.
Automobile has as an engine, and the Engine class is an element of the
Automobile class.
o
Using protected
for Inheritance of a Base Class When a base class is inherited as protected,
all public and protected members of the base class become protected members of
the derived class. You should not have
to worry about knowing this material for this class. An example is shown below for reference.
// Example
#include <iostream>
using namespace std;
class base
{
public:
int _num1;
void setNum3(int num3) { _num3 =
num3; }
int getNum3() const { return
_num3; }
protected:
int _num2;
private:
int _num3;
};
// Inherit class as
protected
class derived : protected base
{
public:
void setNum1(int num1) { _num1 =
num1; }
int getNum1() const { return
_num1; }
void setNum2(int num2) { _num2 =
num2; }
int getNum2() const { return
_num2; }
};
int main()
{
derived X;
X.setNum1(35);
cout << "Number1 =
" << X.getNum1() << endl;
X.setNum2(101);
cout << "Number2 =
" << X.getNum2() << endl;
/*
* The next two lines are not legal because setNum3()
* and getNum3() are
protected members of derived,
* which makes them
inaccessible outside of derived.
*/
// X.setNum3(10);
// cout << "Number3 = " << X.getNum3() << endl;
// The next two lines are illegal for the same reasons.
// X.base::setNum3(14);
// cout << "Number3 = " << X.base::getNum3() << endl;
/*
* The next line is not legal because _num1 is
public
* in the base class,
but is protected in the derived
* class (due to the
protected inheritance), which makes it
*
inaccessible (directly) outside of the derived class.
*/
// X._num1 =
50;
return 0;
}
// Output
Number1 = 35
Number2 = 101
o
Inheriting
Multiple Base Classes Its possible for a derived class to inherit two or
more base classes. However, there can be
complications and ambiguities when doing this should the base classes have the
same member function/variable names. You
should not have to worry about knowing this material for this class. An example is shown below for reference.
// Example
#include <iostream>
using namespace std;
class base1
{
public:
void showNumber1() { cout <<
"Number1 = " << _number1 << endl;
}
protected:
int _number1;
};
class base2
{
public:
void showNumber2() { cout <<
"Number2 = " << _number2 << endl;
}
protected:
int _number2;
};
class derived : public base1,
public base2
{
public:
void set(int number1, int number2);
};
void derived::set(int number1, int number2)
{
_number1 =
number1;
_number2 =
number2;
}
int main()
{
derived X;
X.set(100,
375);
X.showNumber1();
X.showNumber2();
X.set(800,
20);
X.showNumber1();
X.showNumber2();
// Note: Any
attempt at direct access of _number1 or _number2
// will
result in a compiler error because both are protect
// members
of the base class. Thus they are not
accessible
// from main().
return 0;
}
// Output
Number1 = 100
Number2 = 375
Number1 = 800
Number2 = 20