inheritance
DESCRIPTION
Inheritance. Inheritance is a relationship among classes wherein one class shares the structure and/or behavior that is defined in one or more other classes (is-a) Base class – superclass (parent) Derived class (subclass, child). The benefit of inheritance. - PowerPoint PPT PresentationTRANSCRIPT
1
Inheritance Inheritance is a relationship among
classes wherein one class shares the structure and/or behavior that is defined in one or more other classes (is-a)
Base class – superclass (parent) Derived class (subclass, child)
2
The benefit of inheritance The goal of any software is that you could
go back and make changes to the ancestor and be sure those changes will be reflected in all the descendents as well
Example: If you went to a tailor and asked him to make a shirt just like the one he made for you earlier except this time you need a button-down collar, then you would be practicing inheritance
3
Inheritance
Both Student and Teacher is a person
Person
Teacher Student
4
Constructors/Destructors By default, constructors and destructors
inherited from the superclass, will apply to data members inherited from the superclass
Write your own constructors/destructors for the subclass when You add new data members to the subclass
and need to initialize/destroy them You want to change how other data members
are initialized/destroyed
5
Constructors/Destructors Some derived classes need constructors.
If a base class has constructors, then a constructor must be invoked. Default constructors can be invoked implicitly.
However, if all constructors for a base require arguments, then a constructor for that base must be explicitly called.
Arguments for the base class’s constructor are specified in the definition of a derived class’ constructor
6
examplesclass Counter{
protected:unsigned int count;
public:Counter() : count(0) {}Counter(int c) : count(c) {}void print() {cout<<The count is <<count; }Counter operator ++ (){return Counter(++count); }
};class CountDn : public Counter{
public:CountDn() : Counter() {}CountDn(int c) : Counter(c) {}void print() {cout<<The countdown is <<count; }CountDn operator-- (){return CountDn(--count); }
};
7
examplesvoid main(){CountDn c1;Count * p_ = &c1;++c1;c1.print();p->print();
}The countdown is 1The count is 1
8
Order of Creation/Destruction When we create subclass, the
sequence of creation is Call constructor of superclass Call constructor of subclass
When we destroy subclass, the sequence is reverse Call destructor of subclass Call destructor of superclass
9
Copying Derived class might add extra
data:Name
Addressclass Person
classList
Office hours
Class Teacher
10
Copyingclass Employee {
// …
Employee & operator=(const Employee &);
Employee(const Employee &);
};
void f(const Manager & m)
{
Employee e = m; // construct e from m
e = m; // assign Employee part of m to e
} Because Employee copy functions do not know anything about Managers, only
the Employee part of Manager is copied. Can be a source of surprises and errors
11
Copying – another exampleVoid g(Manager mm, Employee ee){
Employee* pe = &mm; // ok, Every Manager is an // EmployeeManager * pm = ⅇ //error: not every employee is //a Manager}
12
Three types of inheritance Public
class D : public B { /* … */ } If B is a public base, its public members can
be used by any function. In addition, its protected members can be used by members and friends of D and members and friends of classes derived from D. Any function can convert D* to B*
This is the most common type of inheritance
13
Public inheritance exampleclass Foo {public:
void function1();void function2();
};class Test : public Foo {Public:
void function3(); // test Have access to function1 and 2};class FooTest:public Test {Public:
void function4(); // FooTest has access to function1, function2, function3
};void main(){ FooTest t1;} // We can call functions 1, 2, 3, 4
14
protected inheritanceclass Foo {public:
void function1();void function2();
};class Test : protected Foo {Public:
void function3(); // Test Have access to function1 and 2};class FooTest:public Test {Public:
void function4(); // FooTest has access to function1, function2, function3
};void main(){ FooTest t1; // We can call functions 3, 4
15
Private inheritanceclass Foo {public:
void function1();void function2();
};class Test : private Foo {public:
void function3(); // Test Have access to function1 and 2};class FooTest : public Test {Public:
void function4(); // FooTest has access to function3};void main(){ FooTest t1; // We can call functions 3, 4
16
Private Inheritance Private – class D : private B { /* …
*/ } If B is a private base, its public and
protected members can be used only by member functions and friends of D. Only friends and members of D can convert D* to a B*
Private inheritance is used to cut long chain of inheritance, and prevent further derivations
17
Protected inheritance Protected – class D : protected B
{ /* … */} If B is a protected base, its public and
protected members can be used only by member functions and friends of D and by member functions and friends of classes derived from D. Only friends and members of D and friends and members of classes derived from D can convert D* to a B*
18
Operations in Base and Derived Classes There are three actions that a derived
class D can take with respect to an operation f() of a base class B: The derived class can inherit the function
B::f() without change The derived class can replace B::f() by
function D::f() performing different action The derived class can extend/specialize
B::f() by a function D::f() calling B::f() and performing other tasks
19
Extending a Base Class Operation
void D::f(){
// Do somethingB::f(); // Utilize functionality from base // class// Do something
}
20
Replace and reuseReplace:Void D::f(){
// Do something different}Re-use:
// Do nothingD x;x.f(); // Calls B::f();
21
Multiple Inheritance A class can be derived from more
than one base class. This is called multiple inheritance
class A class B
class C
22
Syntax class C : public A, public B { /* … */ }; Multiple inheritance can utilize public,
protected, and private inheritance types for each derived class.
Can you think of an example where multiple inheritance is useful ?
23
Ambiguity Suppose class A and class B both have method print() class C : pubic A, public B { /* */}; C c; C.print(); //which of the two is called?
24
Resolution of Ambiguity Use the resolution operator to specify a particular method: c.B::print(); Override print() method in C to call either one
or both base class methods:void C::print(){
B::print();A::print();
}
25
Shared based class
Animal Animal
Horse Bird
Pegasus
26
Shared Based Class Two separate Animal objects are
created when creating an instance of class Pegasus
There is no need to have two instances of object Animal, Pegasus is-an Animal. One Animal.
We can declare virtual base classes to resolve some ambiguity when it is only caused by shared base class:
27
Virtual Base Classes Virtual Base will only maintain one instance
of object Animal. Virtual Base will resolve ambiguity when
invoking base class methods. There is only one base, therefore there is no ambiguity
class Horse : virtual public Animal { }; class Bird : virtual public Animal { }; class Pegasus : public Horse, public Bird { };
28
“Diamond” Inheritance
Animal
Horse Bird
Pegasus
29
Word of Advice Use multiple inheritance in a limited way, since
it adds complexity with “minor benefits” (Reiss) It is difficult to resolve ambiguities Inefficient An operation of a derived class must not put
an object in a state that violates an invariant of the base class. Protected Members allow back door access for
Derived class. Avoid using protected members whenever possible
30
Polymorphism Given a pointer of type base * ( Pointer to
the Base class ), to which derived type does the object pointed to really belong ?
Four answers: Ensure that there is no inheritance
Really? Why do we need inheritance at all ? Place type field in the base class for the
functions to inspect Use dynamic_cast Use virtual functions
31
Polymorphism Place type field in the base class for the
functions to inspectclass Employee {
enum Empl_type {M, E};Employee() : type(E) { }
};class Manager : public Employee {
Manager() { type = M; }};void print(Employee * emp){
switch(emp->type){
case Employee::E:cout << “Employee” << endl;break;case Employee::M:cout << “Manager” << endl;
}}
32
Polymorphism Do you see a problem with this approach?
Adding new derived class will require extensive modifications, which can easily introduce errors
Each Derived class must know that this technique must be implemented. Why do you need to know this???
Are you sue that enum/switch is the best way to implement this strategy.
Performance and memory usage can become unacceptable when there are a lot of derived classes.
33
Virtual functions Another alternative to solve this
problem is to use virtual functions Virtual functions overcome the problems
with the type-field solution by allowing the programmer to declare functions in a base class that can be ( or must be in case of purely virtual functions )redefined in each derived class
Let the compiler worry about using the right function.
34
Example of virtual functionclass Employee {public:// NOTE: must use keyword ‘virtual’ to make function virtualvirtual void print() const {
cout << “Employee” << endl;}};class Manager : public Employee {public:
// NOTE: keyword ‘virtual’ is optional, but signature must // exactly match as in base virtual functionvirtual void print() const {cout << “Manager” << endl;
}};
35
Example of virtual functionvoid print(const Employee * emp) {
// Depending on the run time binding, the program will call appropriate // function: Either Employee::print() or Manager::print()emp->print();
}
int main(){
Employee * emp1 = new Employee();Employee *emp2 = new Manager();
print(emp1);print(emp2);
}Output:
EmployeeManager
36
Example of virtual function So how does the print() function knows if
it deals with Employee class or a manager class?
CallEmployee * emp1 = new Employee();
Performs dynamic ( run time ) binding of virtual function print(), that is, emp1 pointing to Employee object is BINDED to use Employee::print()Employee *emp2 = new Manager();
On the other hand, during run time, emp2 pointing to Manager object is BINDED to use Manager::print() function
So when we invokeemp1->print() // execute Employee::print()emp2->print() // execute Manager::print()
37
Benefit of virtual functions The main benefit that virtual functions
brings to the programmer is to manage ALL objects in a class hierarchy with only ONE pointer.
A virtual function acts as an interface for derived class
The compiler ensures that the right function for the given object is invoked in each case
Virtual functions are most powerful help to the programmer when used with pointers to objects
38
How does it really work?
P
Object
Virtual Table
Virtual table pointer
//All virtual
//functions
//pointers
virtual print()
OREmployee::print()Manager::print()
39
Virtual table During compile time, all virtual function
entries are placed in the virtual table. But only during the run time (dynamic
binding) those entries are filled with pointers/offset to the real functions
Pointers in virtual table that point to virtual members are offsets, which do not depend on object’s location in memory. A pointer to a virtual member can therefore be
safely passed between different address spaces as long as the same object layout is used in both
40
Virtual Table Advantages Can you see why virtual table has more
advantages over previous methods? Gives less chance to the programmer to
make a mistake, and allow programmer concentrate on other things
Most likely virtual table is much faster than anything programmer may design
Uses hash tables, and fixed offsets. Only a matter of doing de-referencing arrays. Performance is almost O(1)
41
Abstract Classes So far we only looked at the concrete
classes. Concrete classes can be instantiated by themselves.
Abstract classes can not be instantiated by themselves. Some classes, such as class Shape, represent
abstract concepts for which objects cannot exist.
Abstract class only make sense as the base of some class derived from it.
42
Abstract Classes Some of the methods in Abstract class can
not possibly provide meaningful definitions for virtual functions.
How do you define this method ?virtual void Shape :: draw() const{ // ???} Shape class is to abstract. Circle is-a shape,
Square is-a shape, polygon is-a shape How many other shapes are there?
43
Abstract Classes We can not give any meaningful
definition to the method Shape::draw() because: We do not know how many possible
Derived classes ( Triangle, Square, Circle, and etc ) will inherit from class Shape
Depending on the nature of each figure, draw() method has to perform completely different functionality
44
Abstract Classes We do not want to define any functionality
for Shape::draw() method We want to force all the derived classes
( Circle, Triangle, and etc ) to define draw() function
We call such function pure virtual functionclass Shape {
// …virtual void draw()=0;
};
45
Pure virtual functions and Abstract classes If a class has at least one pure virtual
function, the class automatically becomes Abstract class.
A pure virtual function that is not defined in a derived class remains a pure virtual function, so the derived class is also an abstract class
int main(){Shape x; // Compiler error, can’t create an instance of // abstract classreturn 0;
}
46
Pure virtual functions Compiler forces the designer of a
derived class to implement (define) all the pure virtual functions that are in base (abstract class). You will get a compiler error if you
forget to do so Better have a compile time checking
than unexpected surprises at a run time.
47
More on binding Employee * pe = new
Manager(“Joe User”); Allocates object manager in memory,
but our view is limited only to Employee.
Employee
Manager
pe
48
More on binding What happens when the programmer
tries to delete a “pe” pointer? delete pe;
This will only de-allocate attributes of the Employee object, keeping Manager’s attributes dangling in the memory. Lost Memory!
The problem can be solved by declaring base class Destructor to be virtual
49
Virtual Destructor By declaring destructor virtual we guarantee
that destructor of the derived class will be executed before executing destructor of the base classclass Employee{
virtual ~Employee() {cout<<“~Employee\n”;}// …
};class Manager : public Employee {
virtual ~Manager() { cout<<“~Manager\n”; }};
50
Virtual destructors
delete pe;Output:~Manager~Employee Note, in case of virtual destructors
we preserve proper cleanup even when we only have base class pointer
51
More on Binding When an object is stored in a variable, the
object is said to be bound to the variable. For example:Employee e(“Joe User”);This statement binds an Employee object with name “Joe User” to the variable e. As the execution of the program progresses, other objects can be bound to ee = Employee(“Karl Schiller”);All objects bound to “e” have the same type, namely Employee
52
More on binding It is possible to assign an object of a
derived type to “e”, but the assignment only copies the Employee sub-object into “e”e = Manager(“Carol Smith”);This forces Manager object to be truncated so it can be fit into Employee object “e”. All Manager specific attributes are lost.
We can use pointers:Employee* pe = new Employee(“Susan Yen”);pe = new Manager(“Carl Johnson”);
53
More on binding Two pointers can share the same object:
Employee* pe1 = pe; Pointers can be bounded to no object at all
pe1 = 0;
Binding and references References can also be bound to an object
of a given class or any derived class
54
More on binding Fields and operations are accessed with
the dot (.) operator, not with -> A reference always have to be bound to
an existing object. It can not change and it can not be null
When they are parameters, they are bound to the object in the call. When function exits, the binding terminates. Compare(Employe & e1, Employee & e2)
55
Static and Dynamic Binding The type of a variable is the static type The type of the object is the dynamic type Testing for a Type Match
C++ provides the typeid() operator to find out whether a base class pointer actually points to a derived class of a certain type
Shape *s;if(typeid(s) == typeid(Rectangle*))// s points to a rectangle object
else// s points to an object of some other class
56
static_cast The static_cast operator coverts
between related types such as one pointer type to another, or floating-point type to an integral type.int *p=static_cast<int*>(new double[10]);
// C style, but works fine in C++int *p=(int *)new double[10];
static_cast is portable, and allows the compiler to apply some minimal type checking and finding dangerous conversions
57
Other casts reinterpret_cast
Handles conversions between unrelated types such as an integer to a pointer.
const_cast Removes constconst Manager *m=new Manager(“Joe”);
Manager * m2=const_cast<Manager*>(m);
58
Downcasting/Widening Sometimes we need to convert a base class pointer
to a concrete derived class pointer to gain access to the derived class features
This process is known as downcasting, or widening C++ has a built in dynamic_cast operator that performs
both the test and type conversion at a run time. dynamic_cast returns back a valid pointer if the object is of
the expected type and a null pointer if it is not. dynamic_cast can also work with references Requires pointer or reference to the polymorphic type
59
Downcasting ExampleShape* s
s = new Rectangle();// ors = new Circle();
Rectangle* r = dynamic_cast<Rectangle*>(s);
if ( r != 0 )// r equals s and points to an object that is a rectangle
else// s points to an object that is not Rectangle
60
dynamic_cast and type checking Dynamic_cast only works with polymorphic
types, however the target type does not have to be polymorphic // Assume Manager derives from abstract class //Employee, and class Date has no inheritance
and // no virtual functions
Manager* manager = new Manager();Date* date = new Date();void *pd1 = dynamic_cast<void*>(manager); //okvoid *pd1 = dynamic_cast<void*>(date); //error
61
dynamic_cast It can cast from a polymorphic virtual
base class to a derived class. We can use static_cast instead, with the
following consequences: Good: Works faster than dynamic cast Bad: Dangerous, we reply on programmer
not making a mistake static_cast can not cast from virtual
base
62
Upcast, narrowing Whenever we want to convert
Derived class into a Base class we call this process upcasting or narrowing
Upcast is safe, as long as we remember to clean up in the end. Use of virtual Destructors
EmployeeManagerUpcast
63
Shallow copy If we want to copy all the entries in
a container holding a collection of objects, we can copy the pointers. Such a copy is called shallow copy
Shallow copies are dangerous If one object gets destroyed, the other
will point to incorrect memory Concept of identity is broken, the
same memory is shared by two objects
64
Deep Copy Polymorphism technique is well suited for
making deep copies of objects Deep copy makes a true copy of the object,
preserving that each object has its own independent set of data ( Object’s identity)class Shape {public:virtual Shape* clone() const=0;};
Shape* Point::clone() const {return new Point(this);}Shape * Rectangle::clone() const{return new Rectangle(this);}
65
Word on delete operatorShape * drawShape[100];//…delete [] drawShape;This is incorrect, since drawShape is notan array of objects. drawShape is anarray of pointers to objectsInstead we need to delete each object:for(int I=0; I<100;I++)
delete drawShape[I];
66
Virtual Constructors? We saw virtual destructors, we
obviously ask “Can the constructors be virtual?”
The answer is NO, to construct an object, constructor needs the exact type of the object it is to create.