·       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 – It’s 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

Hosted by www.Geocities.ws

1