inheritence mark hennessy dept. computer science nui maynooth c++ workshop 18 th – 22 nd september
TRANSCRIPT
Inheritence
Mark Hennessy
Dept. Computer Science
NUI Maynooth
C++ Workshop
18th – 22nd September
What is Inheritance?
Inheritance enables classes to inherit attributes and methods from other classes. It allows the sharing of common elements between classes without having to repeat definitions for each class.
Inheritance occurs between
classes NOT Objects!
Derived & Base Classes (1)
A class does not contain state values – it only defines the methods and attributes which may be used in a class. State values are contained in individual objects.
A derived class inherits the attributes and methods of a base class.
We may build on the derived class by adding attributes and methods.
Derived & Base Classes (2)Base class: a class form which another class inherits.Base classes don’t have to represent anything concrete which could be instantiated as an object of its own.Derived class objects do not inherit any state values from base class objects.The derived class may be extended without effecting the original class..
public inheritance
Person
Student
Every student is a person, but not every person is a student.
C++ compiler enforces this!
Typical design
Person
Student Staff
virtual void print()=0;
void print(); void print();
Person * p = new Student(“Hank”);p->print();
Passing parameters to base class constructor
class Person {public: Person(const string & n) : name(n) {}private: string name;};class Student : public Person{public: Student(const string & n, float g) : Person(n), gpa(g) {}private: float gpa;};
Typical uses of inheritance
Single inheritance – one base class
attributes that describe all classes go in the base class
attributes that are “special” go in derived class
Easy to extend
Can add a new derived class, extending the framework,without changing any existing code: extensibility
is-a doesn’t always work right!
fact: birds can fly
fact: a penguin is a bird
Bird
Penguin
class Bird { virtual void fly() = 0;};
class Penguin : public Bird {};
What’s wrong with this?What’s wrong with this?
C++ Syntax for Inheritance
: denotes inheritance(also called specialisation or derivation or extension)
public derivations and private derivations are possible.
The protected keyword allows derived classes to access inherited attributes.
Public or Private Derivations?
Public derivations: Allow objects of a derived class access to the
public section of the base class.
Private derivations: Allow a derived object to use the methods
defined in the derived class, not those inherited from the base class.
class intObj{private:int val;public:intObj(){val =0;}int getint() const {return val;}void setint(int x){val = x;}void print(){cout <<val<<endl;}};class SubintObj: public intObj{//...}int main(){intObj obj; obj.print();SubintObj Sobj; Sobj.print();}
Public Inheritance in C++
The common syntax is:
derive SubintObj as a subclass of intObj
it is public because it means that the public members of the base class become public members of the derived class.
Question: what can we do with the derived class?
class intObj{protected: int val;public:intObj(){val =0;}int getint() const {return val;}void setint(int x){val = x;}void print(){cout <<val<<endl;}};
class SubintObj: public intObj{public:void inc(){val++;}};
int main(){SubintObj Sobj; Sobj.print(); Sobj.inc();Sobj.print();}
Public Inheritance in C++: add a method
protected : to allow access
This will print out
0
1
class intObj{private:int val;public:intObj(){val =0;}int getint() const {return val;}void setint(int x){val = x;}void print(){cout <<val<<endl;}};
class SubintObj: public intObj{public: int count;SubintObj(){count =0;}};
int main(){SubintObj Sobj; Sobj.print();cout << Sobj.count;}
Public Inheritance in C++: add a data member
Question: how can we make sure that the added data type gets initialised correctly when an object of the derived class is constructed?
Answer: we write a constructor for the derived class (in this case a default constructor with no parameters).
The output is now:
0
0Question: how did val get initialised
on the previous slide??
Parameters?
A derived class will always inherit the constructor of a base class, as well as having its own. The base class constructor is always called first, followed by the constructor of the derived class, and so on down the tree.
If the base constructor takes no parameters inheritance is implicit.
If it takes parameters these must be stated explicitly in each derived class.
An Example:#include <string>class customer{private:
std::string name;public:
{ customer(std::string name_in){name = name_in;}
}}
Inheriting the constructor.
class accountcustomer:public customer
{ private:
int account_number;
public:
accountcustomer(std::string name_in);
};
accountcustomer::accountcustomer(std::string name_in):customer(name_in)
{ // constructor body
}
// SubintObj.cc#include<iomanip>#include<iostream>class intObj{private:int val;public:intObj(){val =0;}int getint() const {return val;}void setint(int x){val = x;}void print(){cout <<"intObj:"<<val<<endl;}};class SubintObj: public intObj{public:void print(){cout <<"SubintObj:"<<getint()<<endl;}};int main(){intObj *obj = new intObj; obj->print();SubintObj *Sobj = new SubintObj; Sobj->print();}
virtual functions & polymorphism
This will produce the output:
intObj:0SubintObj:0
The print functions are polymorphic because they work on different types (classes)
We have already seen polymorphic functions in the same class, where they have different parameter types
Why use virtual functions
place the burden of knowing/choosing the object type on the compilercompiler constructs a vtbl for each class w/ virtual functionone table per class; each class has ptr to vtblvtbl holds pointers to all virtual functionsvptrs init in constructoreach virtual function is invoked thru its vptr
Do virtual functions have performance penalty?
vptr must be init in constructor
virtual function is invoked via pointer indirection
cannot inline virtual functions
more later…
RULE: Never redefine an inherited non-virtual function
class Person {public: string getName() const { return name; }private: string name;};class Student : public Person {};
Student stu;Person * p = &stu;Student * s = &stu;p->getName();s->getName();
Never redefine an inherited non-virtual function
class Person {public: string getName() { return name; }private: string name;};class Student : public Person { string getName(); };
Student stu;Person * p = &stu;Student * s = &stu;p->getName();s->getName();
Non-virtual functions arestatically bound;virtual functions are dynamically bound
Dynamic binding: virtual functions and polymorphism•when the class of the object being pointed at is used (at run time) to decide which method gets executed (its own method)
•it is dynamic because pointers can be used to point at any subclass object
•So, for example, if we define a Pets class with 2 subclasses (dog and cat). Each offers a method makenoise(). If we declare an object, Pugsy say, to be a Pet (or a pointer to a pet), then Pugsy may bark or purr depending on whether it is a dog or a cat.
•The key is that we cannot tell at compile time whether Pugsy is a dog or a cat so the correct method can only be decided at run time
•Unless we want the Pet method makenoise every time (which we usually do not) then we need some mechanism to tell the compiler to bind the method at run time.
•This mechanism is a virtual function in C++.
virtual functions and polymorphism
class intObj{private:int val;public:intObj(){val =10;}int getint() const {return val;}void setint(int x){val = x;}void virtual print(){cout <<"intObj:"<<val<<endl;}};class SubintObj: public intObj{public:SubintObj(){setint(20);}void print(){cout <<"SubintObj:"<<getint()<<endl;}};int main(){intObj obj;SubintObj Sobj; intObj* objPt;objPt = &Sobj; objPt->print();objPt =&obj; objPt->print();}
The output is:
SubintObj:20
intObj:10
So, in this case we have the ‘correct’ method used at run time
Pets and virtual functions example.
// Pets.cc#include<iomanip>#include<iostream>#include<string>
class Pet{public:string name;Pet(){name = "pet";}void print(){cout <<"The Pet is called "<< name<<endl;}};
class Dog: public Pet{public:Dog(){name = "dog";}void print(){cout <<"The Dog is called "<<name<<endl;}};
class Cat: public Pet{public:Cat(){name = "cat";}void print(){cout <<"The Cat is called "<<name<<endl;}};
int main(){Pet p;p.print();Dog d;d.print();Cat c;c.print();}
Pets: Cats and Dogs
The Pet is called petThe Dog is called dogThe Cat is called cat
class Pet{public:void virtual makenoise(){cout << "pet says " <<endl;}};
class Dog: public Pet{public:void makenoise(){cout << "dog says woof" <<endl;}};
class Cat: public Pet{public:void makenoise(){cout << "cat says meaow" <<endl;}};
int main(){Pet *p1, *p2; Cat c; Dog d;p1 =&c; p2 =& d;p1->makenoise();p2->makenoise();}
Back to Pets, Cats and Dogs
Output:cat says meaowdog says woof
virtual
pointers to objects
Pet
Dog Cat