+ All Categories
Home > Documents > Inheritance Version 1.1. Topics Inheritance Constructors and Inheritance Function Over-riding...

Inheritance Version 1.1. Topics Inheritance Constructors and Inheritance Function Over-riding...

Date post: 01-Jan-2016
Category:
Upload: sabrina-cox
View: 227 times
Download: 1 times
Share this document with a friend
Popular Tags:
54
Inheritanc e Version 1.1
Transcript

InheritanceVersion 1.1

Topics

InheritanceConstructors and InheritanceFunction Over-riding (Redefinition)The Stringstream classShadowing VariablesDestructors and InheritancePointers and InheritanceUpcasting and DowncastingMultiple Inheritance

Objectives

After completing this topic, students should be able to:

Correctly design and use classes that use public inheritancein a C++ program* Know how to correctly call the parent constructor* know how to over-ride functions in the parent classWrite functions that generate a string representation of aclass, using the stringstream classDescribe the differences between upcasting and downcastingand know when to safely use eachCorrectly use multiple inheritance in a program

Inheritance is the act of deriving a new classfrom an already existing class. Analogous to creating a new house blueprint from anexisting one.

Inheritance is useful when we find a naturalhierarchical relationship between classes.

Inheritance makes it possible to re-use existingcode (classes), thus saving time and minimizing bugs.

Example and Terminology

Suppose that we are creating a newrole playing game, and we want tohave the following creatures:

Dwarf Elf Fairy

All of these are “creatures “. They all have • A name

• A strength value• A hitpoint value

Dwarf Elf Fairy

We could define a class for each such as:

class Dwarf{ private: string name; int strength; int hitpoints; //other dwarf stuff public: Dwarf( ); getDamage( ); //other dwarf stuff};

class Elf{ private: string name; int strength; int hitpoints; //other elf stuff public: Elf( ); getDamage( ); //other elf stuff};

class Fairy{ private: string name; int strength; int hitpoints; // other fairy stuff public: Fairy( ); getDamage( ); //other fairy stuff};

Note that all of these classes have some things in common

class Dwarf{ private: string name; int strength; int hitpoints; … other … public: Dwarf( ); getDamage( ); . . .};

class Elf{ private: string name; int strength; int hitpoints; … other … public: Elf( ); getDamage( ); . . .};

class Fairy{ private: string name; int strength; int hitpoints; … other … public: Fairy( ); getDamage( ); . . .};

And they have some things that are different

class Dwarf{ private: string name; int strength; int hitpoints; // dwarf stuff public: Dwarf( ); getDamage( ); // dwarf stuff};

class Elf{ private: string name; int strength; int hitpoints; // elf stuff public: Elf( ); getDamage( ); // elf stuff};

class Fairy{ private: string name; int strength; int hitpoints; //fairy stuff public: Fairy( ); getDamage( ); // fairy stuff};

We gain a lot of productivity and functionality if we factor the common

elements out into a base class.

Creaturenamestrengthhitpoints

Dwarf Elf Fairy

Base class

Derived Class

Sometimes also called• parent class• super class

Sometimes also called• child class• sub class

This relationship is calledInheritance.

If elves and fairies are both magicalcreatures, we might envision another

layer of base and derived class

Creaturenamestrengthhitpoints

Dwarf

Base class

Derived ClassMagicalCreature

spells

Elf Fairy

Derived Class

This is known as a class hierarchy

Creaturenamestrengthhitpoints

Dwarf

MagicalCreature

spells

Elf Fairy

Dwarf inheritsfrom Creature

Elf and Fairy inheritfrom Magical Creature

Magical Creatureinherits from Creature

This is known as a class hierarchy

Creaturenamestrengthhitpoints

Dwarf

MagicalCreature

spells

Elf Fairy

Common things are definedin base classes

Unique things are definedin derived classes

the protected modifier (#) tells usthat the variable name is accessiblefrom within the Creature class andfrom within any derived classes. That is,functions of the derived class can see theprotected data members defined in the base class.

Creaturenamestrengthhitpoints

Let’s look at the base class definition

Class Creature{ protected: string name; int strength; int hitpoints; public: Creature( ); int getDamage( ); . . .};

Creaturenamestrengthhitpoints

And the MagicalCreature class

Class MagicalCreature : public Creature{ protected: int spells; public: MagicalCreature( ); . . .};

The keyword public means that this class will inherit publicly from theCreature class. That is, a MagicalCreatureobject will have everything that a Creatureobject has, and everything declared as publicin the base class will be public in the derived class.

MagicalCreature

spells

So . . . If I create a MagicalCreatureobject named Zor, then Zor has the following properties:• name• strength• hitpoints

• spells - This comes from the MagicalCreature class

These come from the Creature class

This kind of inheritance is known asan is-a (is-like-a) relationship. That is, a MagicalCreature is a Creature.

An object of the MagicalCreature class can be used anyplace that an object of the Creature class can be used.

Let’s look at how we deal with differences between classes by Looking at the

getDamage( ) function..

Dwarf Elf Fairy

getDamage( ) computes and returns the damage thatthis creature inflicts in one round of combat.

Every creature inflicts damage that is a random numberbetween 1 and the creature’s strength value.

Dwarves are good fighters, andhave a 25% chance ofinflicting an additional

50 damage points

Magical creatures can double thedamage points if they have a magic spell.

Fairies are very quick, sothey get to attack twice.

Creaturenamestrengthhitpoints

Since the damage that any creature can inflictis defined as a random number between 0 and the creature’s strength value, we could writethe following code in the base class:

int Creature::getDamage( ){ int damage = (rand( ) % strength) + 1; return damage;}

Creaturenamestrengthhitpoints

Dwarves have a 25% chance of inflicting an additional 50 damage points. So thegetDamage( ) function in the Dwarf class might look like:

int Dwarf::getDamage( ){ int damage = (rand( ) % strength) + 1; if (rand( ) % 100 < 25) damage = damage + 50; return damage;}

Dwarf

Creaturenamestrengthhitpoints

int Dwarf::getDamage( ){ int damage = (rand( ) % strength) + 1; if (rand( ) % 100 < 25) damage = damage + 50; return damage;} Dwarf

int Creature::getDamage( ){ int damage = (rand( ) % strength) + 1; return damage;}

Notice that both the Creature class and the Dwarf classhave a function named getDamage( );

This is called Function Over-riding.

We over-ride, a member function in the base class by writing a similar function in the derivedclass that has exactly the same signature, but with a different implementation.

Function Over-riding

This is also called function re-definition.

dwarf01

So, if I create a Dwarf object nameddwarf01, and send dwarf01 a getDamage( )message . . .

dwarf01.getDamage( )

The getDamage( ) function in the Dwarf class over-ridesthe getDamage( ) function in the base class, and so thegetDamage( ) function in the Dwarf class gets executed.

Note that if we had not re-defined the getDamage( )function in the Dwarf class, then it would have beenthe getDamage( ) function from the base class thatwould have been executed. This is because a Dwarfis-a (is-like-a) creature.

dwarf

Let’s let dwarves have a unique propertyof size. The class definition then might be:

Class Dwarf : public Creature{ private: int size; public: Dwarf( ); Dwarf(string, int, int, int); int getDamage( ); . . .};

Now create a Dwarf object …

Dwarf dwarf01 ( “Rohan”, 350, 500, 25);

dwarf01

name

strength

hitPoints

When the constructor is called, thecomputer looks at the Dwarf classto see how much storage to allocate.It notes that a Dwarf is a Creature,so it looks at the Creature class also.Enough storage is allocated for thedata members of both the base and the derived classes. size

Creature Part

Dwarf Part

Dwarf::Dwarf (string _nme, int _strngth, int _hpts, int _sze) : Creature (_nme, _strngth, _hpts){ size = _sze;}

The Dwarf Constructor

Constructors are not inherited. Inorder to initialize the parent class wemust invoke the base class constructor.This is done with an initializer list.

If you do not explicitly call the Creatureconstructor, the default Creature constructoris called automatically

Shadowing Variables

If a child class declares a variable using the same nameas a variable in a parent class, the variable in the child class is said to shadow the variable in the parent.

Shadowing variables is not usually recommended.

The Stringstream class

The stringstream classes support reading from or writingto a buffer in memory, just as if we were reading from orwriting to a stream.

#include <iostream>#include <sstream>using namespace std;

int main( ){ double number = 3.21467; ostringstream s, t; s << "Hello World!"; t << "\nGoodbye Cruel World!"; t << “\nnumber = “ << number; cout << s.str( ) + t.str( ); system(“PAUSE”); return 0;}

ostringstream acts justlike an output stream class.

The stringstream classes support reading from or writingto a buffer in memory, just as if we were reading from orwriting to a stream.

#include <iostream>#include <sstream>using namespace std;

int main( ){ double number = 3.21467; ostringstream s, t; s << "Hello World!"; t << "\nGoodbye Cruel World!"; t << “\nnumber = “ << number; cout << s.str( ) + t.str( ); system(“PAUSE”); return 0;}

Use stream insertionjust like with any otheroutput stream object

The stringstream classes support reading from or writingto a buffer in memory, just as if we were reading from orwriting to a stream.

#include <iostream>#include <sstream>using namespace std;

int main( ){ double number = 3.21467; ostringstream s, t; s << "Hello World!"; t << "\nGoodbye Cruel World!"; cout << s.str( ) + t.str( ); system(“PAUSE”); return 0;}

ostringstream has a memberfunction str( ) that returnsthe contents of the stream as a string.

Lets make it possible for each creature togenerate an output string describing itself.

My name is Rohan. My strength is 300 and myhitpoint value is 200. I am a dwarf and my size is 3.

My name is Elgier. My strength is 235 and myhitpoint value is 90. I am a magical creature andI have 3 spells. I am an Elf.

My name is Moondrops My strength is 190 and myhitpoint value is 75. I am a magical creature andI have 3 spells. I am a fairy and my speed is 16.

The toString( ) function in the Base class:

string Creature::toString( ){ ostringstream creatureOut; creatureOut << “My name is “ << name << “.\n” << “My strength is “ << strength << “,\n” << “my hitpoint value is “ << hitPoints << “.”; return creatureOut.str( );}

The toString( ) function in the MagicalCreature class:

string MagicalCreature::toString( ){ ostringstream magicalOut; magicalOut << “I am a Magical Creature, and I have ” << spells << “ spells.”;

return this->Creature::toString( ) + magicalOut.str( );}

The toString( ) function in the Fairy class:

string Fairy::toString( ){ ostringstream fairyOut; fairyOut << “I am a fairy, and my speed is “ << speed << “.”;

return this->MagicalCreature::toString( ) + fairyOut.str( );}

cout << bestFairy.toString( )

string Fairy::toString( ){ ostringstream fairyOut; fairyOut << “I am a fairy, and my speed is “ << speed << “.”; return this->MagicalCreature::toString( ) + fairyOut.str( );}

invokes

string MagicalCreature::toString( ){ ostringstream magicalOut; magicalOut << “I am a Magical Creature, and I have ” << spells << “ spells.”; return this->Creature::toString( ) + magicalOut.str( );}

invokes

invokes

string Creature::toString( ){ ostringstream creatureOut; creatureOut << “My name is “ << name << “.\n” << “My strength is “ << strength << “,\n” << “my hitpoint value is “ << hitPoints << “.”; return creatureOut.str( );}

Destructors

Destructors are not inherited. However, when adestructor in a derived class is invoked, it automatically invokes the destructor for thebase class.

Order of Construction and Destruction

When an object of a derived class is created,the derived class constructor is called first, it thencalls the base class constructor. The base classconstructor completes and then the derived classconstructor completes.

Destruction occurs in the opposite order.The derived class destructor is called (destroys the derived object), it completes then it calls the base class destructor which destroys the base object and completes.

Protected Inheritance

A derived class can be defined using protected inheritance,as

class Circle : protected Shape { …

Protected inheritance means that public data in thebase class becomes protected in the derived classwhen it is inherited.

Private Inheritance

A derived class can be defined using private inheritance,as

class Circle : private Shape { …

Private inheritance means that public data in thebase class becomes private in the derived classwhen it is inherited.

Visibility

In the case of public inheritance

Member functions in a derived class can access Public data and functions in the base class Protected data and functions in the base class

Functions outside of the derived class can access public data and functions in the base class public data and functions in the derived class

Inheritance and Pointers

Because of the is-a (is-like-a) relationship, an object of a publiclyderived class can always be treated as an object of thecorresponding base class.

In particular, you can always store the address of aderived class object in a base class pointer.

Dwarf littleDwarf (“Egrew”, 600, 500, 2);

Creature* littleCreaturePtr;

littleCreaturePtr = &littleDwarf;

littleDwarf

littleCreaturePtr

littleDwarf isA Dwarf object.

littleCreaturePtr isa Creature pointer.

If you now use the Creature pointer, it treatslittleDwarf as if it were an creature. For example …

littleDwarf

littleCreaturelPtr

cout << littleCreaturePtr -> toString( );

string Creature::toString( ){ ostringstream creatureOut; creatureOut << “My name is “ << name << “.\n” << “My strength is “ << strength << “,\n” << “my hitpoint value is “ << hitPoints << “.”; return creatureOut.str( );}

invokes

This works because the derived class object is reallymade up of two parts, the base class part and thederived class part. The base class pointer just points to the base class part.

littleDwarf

littleCreaturePtr

basepart

derivedpart

You can store the address of a base class objectin a derived class pointer, but you must do anexplicit downcast first!

Dwarf *littleDwarf;Creature anyOne (“joe”, 400, 190);

littleDwarf = (Dwarf*) (&anyOne);

This is pretty dangerous and not often used, becausethe derived class pointer thinks it is pointing to aderived class object, but it really isn’t. This isreferred to as the “slicing problem”.

joe

littleDwarf

basepart

there is no derived part.If you try to access memberdata in the derived part, youwill get garbage!

Upcasting vs. Downcasting

Casting from a descendant type to an ancestor type is known as upcasting (widening cast). It is always safe, since you are moving up the inheritance hierarchy. In our case, for example, we are always know that a Dwarf is an Creature.

Casting from an ancestor type to a descendant typeis called downcasting (narrowing cast). In our case, we can’t guarantee that every creature is a Dwarf, so downcasting a Creature to a Dwarf can be very dangerous, since we assume that information may be there that isn’t.

Multiple Inheritance

In C++, a derived class can have many parents,for example …

class MotorHome : public Vehicle, public House{ …

parents are separated by commas

class MotorHome :public Vehicle, public House{ …

construction starts with the leftmostparent and proceeds to the right.

Vehicle is created firstThen HouseFinally MotorHome is created

Ambiguity Errors

One of the major issues with multiple inheritanceis ambiguity. For example, suppose that the Houseclass and Vehicle class both have a function namedturnLightsOn. What happened in the following case:

MotorHome myRV;

myRV.turnLightsOn( );

the compiler gives you an ambiguity error.


Recommended