Presentation is loading. Please wait.

Presentation is loading. Please wait.

Inheritance Version 1.1. Topics Inheritance Constructors and Inheritance Function Over-riding (Redefinition) The Stringstream class Shadowing Variables.

Similar presentations


Presentation on theme: "Inheritance Version 1.1. Topics Inheritance Constructors and Inheritance Function Over-riding (Redefinition) The Stringstream class Shadowing Variables."— Presentation transcript:

1 Inheritance Version 1.1

2 Topics Inheritance Constructors and Inheritance Function Over-riding (Redefinition) The Stringstream class Shadowing Variables Destructors and Inheritance Pointers and Inheritance Upcasting and Downcasting Multiple Inheritance

3 Objectives After completing this topic, students should be able to: Correctly design and use classes that use public inheritance in a C++ program * Know how to correctly call the parent constructor * know how to over-ride functions in the parent class Write functions that generate a string representation of a class, using the stringstream class Describe the differences between upcasting and downcasting and know when to safely use each Correctly use multiple inheritance in a program

4 Inheritance is the act of deriving a new class from an already existing class. Analogous to creating a new house blueprint from an existing one. Inheritance is useful when we find a natural hierarchical relationship between classes. Inheritance makes it possible to re-use existing code (classes), thus saving time and minimizing bugs.

5 Example and Terminology

6 Suppose that we are creating a new role playing game, and we want to have the following creatures: DwarfElfFairy

7 All of these are “creatures “. They all have A name A strength value A hitpoint value DwarfElfFairy

8 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 };

9 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( );... };

10 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 };

11 We gain a lot of productivity and functionality if we factor the common elements out into a base class. Creature name strength hitpoints DwarfElf Fairy Base class Derived Class Sometimes also called parent class super class Sometimes also called child class sub class This relationship is called Inheritance.

12 If elves and fairies are both magical creatures, we might envision another layer of base and derived class Creature name strength hitpoints Dwarf Base class Derived Class Magical Creature spells Elf Fairy Derived Class

13 This is known as a class hierarchy Creature name strength hitpoints Dwarf Magical Creature spells ElfFairy Dwarf inherits from Creature Elf and Fairy inherit from Magical Creature Magical Creature inherits from Creature

14 This is known as a class hierarchy Creature name strength hitpoints Dwarf Magical Creature spells ElfFairy Common things are defined in base classes Unique things are defined in derived classes

15 the protected modifier (#) tells us that the variable name is accessible from within the Creature class and from within any derived classes. That is, functions of the derived class can see the protected data members defined in the base class. Creature name strength hitpoints Let’s look at the base class definition Class Creature { protected: string name; int strength; int hitpoints; public: Creature( ); int getDamage( );... };

16 Creature name strength hitpoints And the MagicalCreature class Class MagicalCreature : public Creature { protected: int spells; public: MagicalCreature( );... }; The keyword public means that this class will inherit publicly from the Creature class. That is, a MagicalCreature object will have everything that a Creature object has, and everything declared as public in the base class will be public in the derived class. Magical Creature spells

17 So... If I create a MagicalCreature object named Zor, then Zor has the following properties: name strength hitpoints spells - This comes from the MagicalCreature class These come from the Creature class

18 This kind of inheritance is known as an 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.

19 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 that this creature inflicts in one round of combat. Every creature inflicts damage that is a random number between 1 and the creature’s strength value.

20 Dwarves are good fighters, and have a 25% chance of inflicting an additional 50 damage points Magical creatures can double the damage points if they have a magic spell. Fairies are very quick, so they get to attack twice.

21 Creature name strength hitpoints Since the damage that any creature can inflict is defined as a random number between 0 and the creature’s strength value, we could write the following code in the base class: int Creature::getDamage( ) { int damage = (rand( ) % strength) + 1; return damage; }

22 Creature name strength hitpoints Dwarves have a 25% chance of inflicting an additional 50 damage points. So the getDamage( ) 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

23 Creature name strength hitpoints 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 class have a function named getDamage( ); This is called Function Over-riding.

24 We over-ride, a member function in the base class by writing a similar function in the derived class that has exactly the same signature, but with a different implementation. Function Over-riding This is also called function re-definition.

25 dwarf01 So, if I create a Dwarf object named dwarf01, and send dwarf01 a getDamage( ) message... dwarf01.getDamage( ) The getDamage( ) function in the Dwarf class over-rides the getDamage( ) function in the base class, and so the getDamage( ) function in the Dwarf class gets executed.

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

27 dwarf Let’s let dwarves have a unique property of size. The class definition then might be: Class Dwarf : public Creature { private: int size; public: Dwarf( ); Dwarf(string, int, int, int); int getDamage( );... };

28 Now create a Dwarf object … Dwarf dwarf01 ( “Rohan”, 350, 500, 25); dwarf01 name strength hitPoints When the constructor is called, the computer looks at the Dwarf class to 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 the data members of both the base and the derived classes. size Creature Part Dwarf Part

29 Dwarf::Dwarf (string _nme, int _strngth, int _hpts, int _sze) : Creature (_nme, _strngth, _hpts) { size = _sze; } The Dwarf Constructor Constructors are not inherited. In order to initialize the parent class we must invoke the base class constructor. This is done with an initializer list. If you do not explicitly call the Creature constructor, the default Creature constructor is called automatically

30 Shadowing Variables If a child class declares a variable using the same name as 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.

31 The Stringstream class

32 The stringstream classes support reading from or writing to a buffer in memory, just as if we were reading from or writing to a stream. #include 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 just like an output stream class.

33 The stringstream classes support reading from or writing to a buffer in memory, just as if we were reading from or writing to a stream. #include 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 insertion just like with any other output stream object

34 The stringstream classes support reading from or writing to a buffer in memory, just as if we were reading from or writing to a stream. #include 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 member function str( ) that returns the contents of the stream as a string.

35 Lets make it possible for each creature to generate an output string describing itself. My name is Rohan. My strength is 300 and my hitpoint value is 200. I am a dwarf and my size is 3. My name is Elgier. My strength is 235 and my hitpoint value is 90. I am a magical creature and I have 3 spells. I am an Elf. My name is Moondrops My strength is 190 and my hitpoint value is 75. I am a magical creature and I have 3 spells. I am a fairy and my speed is 16.

36 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( ); }

37 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( ); }

38 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( ); }

39 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 string Creature::toString( ) { ostringstream creatureOut; creatureOut << “My name is “ << name << “.\n” << “My strength is “ << strength << “,\n” << “my hitpoint value is “ << hitPoints << “.”; return creatureOut.str( ); }

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

41 Order of Construction and Destruction When an object of a derived class is created, the derived class constructor is called first, it then calls the base class constructor. The base class constructor completes and then the derived class constructor 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.

42 Protected Inheritance A derived class can be defined using protected inheritance, as class Circle : protected Shape { … Protected inheritance means that public data in the base class becomes protected in the derived class when it is inherited.

43 Private Inheritance A derived class can be defined using private inheritance, as class Circle : private Shape { … Private inheritance means that public data in the base class becomes private in the derived class when it is inherited.

44 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

45 Inheritance and Pointers Because of the is-a (is-like-a) relationship, an object of a publicly derived class can always be treated as an object of the corresponding base class. In particular, you can always store the address of a derived class object in a base class pointer.

46 Dwarf littleDwarf (“Egrew”, 600, 500, 2); Creature* littleCreaturePtr; littleCreaturePtr = &littleDwarf; littleDwarf littleCreaturePtr littleDwarf is A Dwarf object. littleCreaturePtr is a Creature pointer.

47 If you now use the Creature pointer, it treats littleDwarf as if it were an creature. For example … littleDwarf littleCreaturelPtr cout 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

48 This works because the derived class object is really made up of two parts, the base class part and the derived class part. The base class pointer just points to the base class part. littleDwarf littleCreaturePtr base part derived part

49 You can store the address of a base class object in a derived class pointer, but you must do an explicit downcast first! Dwarf *littleDwarf; Creature anyOne (“joe”, 400, 190); littleDwarf = (Dwarf*) (&anyOne);

50 This is pretty dangerous and not often used, because the derived class pointer thinks it is pointing to a derived class object, but it really isn’t. This is referred to as the “slicing problem”. joe littleDwarf base part there is no derived part. If you try to access member data in the derived part, you will get garbage!

51 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 type is 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.

52 Multiple Inheritance In C++, a derived class can have many parents, for example … class MotorHome : public Vehicle, public House { … parents are separated by commas

53 class MotorHome :public Vehicle, public House { … construction starts with the leftmost parent and proceeds to the right. Vehicle is created first Then House Finally MotorHome is created

54 Ambiguity Errors One of the major issues with multiple inheritance is ambiguity. For example, suppose that the House class and Vehicle class both have a function named turnLightsOn. What happened in the following case: MotorHome myRV; myRV.turnLightsOn( ); the compiler gives you an ambiguity error.


Download ppt "Inheritance Version 1.1. Topics Inheritance Constructors and Inheritance Function Over-riding (Redefinition) The Stringstream class Shadowing Variables."

Similar presentations


Ads by Google