Download presentation
Presentation is loading. Please wait.
1
C++ Programming Inheritance
Design Example classes Virtual functions Pure virtual functions Abstract classes
2
Relationships between Classes "Is a"
The relationship "Is a" ( "Inherits from") A class (A) can inherit the state (variables) and behaviour (methods) of another class (B) We say class A is a base class (or a generalization, or a super-type) of class B and class B is a class derived from Class A (or a specialization, or a subtype) For example, leptons, hadrons, bosons are all particles, but belong to different groups, each with their special properties Particle Lepton Hadron Boson
3
Example To demonstrate the design and implementation of the inheritence we will develop classes that describe typical family pets Let's try to find common characteristics typical of our pets - cats and dogs Each one has a name They eat - we give them food They “speak” - dogs bark, cats meow Specific behaviours: Cats hunt mice Dogs guard home
4
Design ... Dog name Eat() Speak() Cat name Eat() Speak() Pet name Eat() Speak() The common data members and functions can be regrouped in a base class Pet (The specific behaviors will be considered later) Dog Cat
5
Classes (definition) Declaration of the inheritance relationship
#include <string> class Pet { public: Pet(std::string name); void Eat(); void Speak(); std::string Name(); private: std::string m_name; }; #include “Pet.h” #include <string> class Dog : public Pet { public: Dog(std::string name); }; Declaration of the inheritance relationship #include “Pet.h” #include <string> class Cat : public Pet { public: Cat(std::string name); }; Pet name Eat() Speak() Dog Cat
6
Classes (implementation)
#include "Pet.h" #include <iostream> Pet::Pet(std::string name) : m_name(name) { } void Pet::Eat() { std::cout << m_name << " eats" << std::endl; void Pet::Speak() { std::cout << m_name << " speaks" << std::endl; std::string Pet::Name() { return m_name; #include "Dog.h" #include <iostream> Dog::Dog(std::string name) : Pet(name) { } #include "Cat.h" #include <iostream> Cat::Cat(std::string name) : Pet(name) { } Pet name Eat() Speak() Initialisation of the base class Dog Cat
7
Classes (use of) ... main1.cxx
#include "Dog.h" #include "Cat.h" int main() { Dog dog("Lassie"); Cat cat("Tilly"); Cat cat2("Tom"); // When you arrive at home pets welcome you dog.Speak(); cat.Speak(); cat2.Speak(); // We have to feed them dog.Eat(); cat.Eat(); cat2.Eat(); } main1.cxx Declaration of objects with their specific types (by derived classes) Calling functions defined in the base class [localhost]> ./atHome1 Lassie speaks Tilly speaks Tom speaks Lassie eats Tilly eats Tom eats
8
... Classes (use of) main.cxx
The existence of the base class allows us to use our objects in generic way #include "Dog.h" #include "Cat.h" #include <vector> int main() { // The collection of our pets std::vector<Pet*> ourPets; ourPets.push_back(new Dog("Lassie")); ourPets.push_back(new Cat("Tilly")); ourPets.push_back(new Cat("Tom")); // When you arrive at home pets welcome you std::vector<Pet*>::iterator it; for ( it=ourPets.begin(); it != ourPets.end(); it++ ) { Pet* pet = *it; pet->Speak(); } /// We have to feed them (*it)->Eat(); Using objects by their base type (Pet *) [localhost]> ./atHome Lassie speaks Tilly speaks Tom speaks Lassie eats Tilly eats Tom eats
9
Specialization of functions ...
We will make our model more precise: The Dog eats the granules ProPlan The Cat eat the cans Whiskas The Dog barks The Cat meow Modelling: Pet name Eat() Speak() Each derived class redefines the functions of the base class Dog Eat() Speak() Cat Eat() Speak()
10
... Specialization of functions
We will add these methods to the classes Dog and Cat For the correct function to be called, it must be declared as being virtual The "correct" function = the function defined for the class whose dynamic type corresponds to the object The object defined by reference Pet1 is of Dog type, Pet2 of Cat type The virtual function acts as an interface to the functions defined in the base class and all the derived classes #include <string> class Pet { public: Pet(std::string name); virtual void Eat(); virtual void Speak(); private: std::string m_name; }; #include “Pet.h” #include <string> class Dog : public Pet { public: Dog(std::string name); virtual void Eat(); virtual void Speak(); }; #include “Pet.h” #include <string> class Cat : public Pet { public: Cat(std::string name); virtual void Eat(); virtual void Speak(); }; It is not obligatory to re-declare virtual functions in derived classes, but it's good practice to do so La déclaration de la relation de héritage
11
... Specialization of functions ...
In implementing these functions, there is nothing special: Dog::Eat() { std::cout << Name() << " eats the granules ProPlan " << std::endl; } void Dog::Speak() { std::cout << Name() << ": woof, woof !! " << std::endl; Cat::Eat() { std::cout << Name() << " eats the cans Whiskas “ << std::endl; } void Cat::Speak() { std::cout << Name() << ": meow, meow !! " << std::endl;
12
... Specialization of functions
We compiles and run the two programs again: [localhost] > ./atHome1 Lassie: woof, woof !!! Tilly: meow, meow !!! Tom: meow, meow !!! Lassie eats the granules ProPlan Tilly eats the cans Whiskas ... If objects were declared with their specific types (through derived classes) If objects were declared with their generic type (through a base class) [localhost]> ./atHome Lassie speaks Tilly speaks Tom speaks Lassie eats Tilly eats ... [localhost] > ./atHome Lassie: woof, woof !!! Tilly: meow, meow !!! Tom: meow, meow !!! Lassie eats the granules ProPlan Tilly eats the cans Whiskas ... When functions are not declared virtual, it is the function of the declared type that is called, without taking into account the actual type of object When functions are declared virtual, it is the function of the real type of object, which is called
13
If You Buy a Canary We add a new class derived from the class Pet:
#include “Pet.h” #include <string> class Canary : public Pet { public: Canary(std::string name); }; #include "Canary.h" #include <iostream> Canary::Canary(std::string name) : Pet(name) { } The Canary class does not specify the methods of the base class main4.cxx // ... #include "Canary.h" int main() { Canary* canary = new Canary("Robbie"); ourPets.push_back(canary); } [localhost]> ./atHome Lassie: woof, woof !!! Tilly: meow, meow !!! Tom: meow, meow !!! Robbie speaks Lassie eats the granules ProPlan Tilly eats the cans Whiskas Tom eats the cans Whiskas Robbie eats
14
Pure Virtual Functions ...
We are going to re-examine the requirements of our program Imagine that we leave our pets to our neighbour and ask them to replace us during our holidays Our program will help him know the needs of our pets: But what does Robbie eat ? Our base class enabled us avoid to specify the needs of our canary [localhost]> ./atHome Lassie: woof, woof !!! Tilly: meow, meow !!! Tom: meow, meow !!! Robbie speaks Lassie eats the granules ProPlan Tilly eats the cans Whiskas Tom eats the cans Whiskas Robbie eats
15
... Pure Virtual Functions ...
The base class can require all derived classes to implement a function: To do this the function must be declared as a pure virtual function #include <string> class Pet { public: Pet(std::string name); virtual void Eat() = 0; virtual void Speak(); private: std::string m_name; }; void Pet::Eat() { std::cout << m_name << " eats" << std::endl; } The pure virtual functions have no implementation
16
... Pure Virtual Functions
We try to compile our program ... and it does not compile! It is impossible to create an instance: of the class that has not defined all inherited pure virtual functions Classes whose instance cannot be created are called abstract classes [localhost] > g++ -I. *.cxx -o atHome4 main4.cxx: In function ‘int main()’: main4.cxx:10: error: cannot allocate an object of abstract type ‘Canary’ Canary.h:4: note: because the following virtual functions are pure within ‘Canary’: Pet.h:10: note: virtual void Pet::Eat() Pet.h:11: note: virtual void Pet::Speak()
17
Specific functions ... We will consider specific behaviors:
The cat chases the mouse Dog guards house Dog name Eat() Speak() Guard() Cat name Eat() Speak() HuntMice Pet name Eat() Speak() The specific functions are added only in derived classes Dog Guard() Cat HuntMice()
18
... Specific functions ... main1.cxx main.cxx
#include "Dog.h" #include "Cat.h" int main() { Dog dog("Lassie"); Cat cat("Tilly"); Cat cat2("Tom"); // When you arrive at home pets welcome you dog.Speak(); ... // We have to feed them dog.Eat(); // And everyone continues in their work dog.Guard(); cat.HuntMice(); } main1.cxx main.cxx #include "Dog.h" #include "Cat.h" #include <vector> int main() { // The collection of our pets std::vector<Pet*> ourPets; ourPets.push_back(new Dog("Lassie")); ... // When you arrive at home pets welcome you // We have to feed them // And everyone continues in their work for ( it=ourPets.begin(); it != ourPets.end(); it++ ) { Pet* pet = *it; Dog* dog = dynamic_cast<Dog*>(pet); If ( dog ) dog->Guard(); Cat* cat = dynamic_cast<Cat*>(pet); If ( cat ) cat->HuntMice(); } The specific functions can not be called in a generic way\
19
Conclusions The class inheritance allows us
Avoid duplication of common code By a common implementation in the base class Process objects in a generic way Collections of objects by the type of base class Call functions with the common interface By declaring virtual functions Forcing Derived classes implement the interfaces required Declaring pure virtual functions
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.