Download as pdf or txt
Download as pdf or txt
You are on page 1of 97

Polymorphism

1
Agenda
• What is Polymorphism
• Why polymorphism
• Static and late binding
• Virtual functions
• Type of polymorphism
• Pure virtual functions
• Abstract class
• Virtual inheritance

2
Object-Oriented Concepts
• Data Abstarction
• Encapsulation
• ADT, Object
• Inheritance
• Derived object
• Polymorphism
• Each object knows what it is

3
Polymorphism
• noun, the quality or state of being able to assume
different forms - Webster
• Virtual means existing in appearance but not in reality
• Polymorphism means “many shapes.” It refers to the
ability of one object to have many types. If we have a
function that expects a Vehicle object, we can safely
pass it a Car object, because every Car is also a Vehicle.
Likewise for references and pointers: anywhere you can
use a Vehicle *, you can use a Car *.
• The sending instance does not need to know the
receiving instance’s class and this class can be any class.

4
Before we proceed….
• Inheritance – Basic Concepts
• Class Hierarchy
• Code Reuse, Easy to maintain
• Type of inheritance : public, private, protected
• Function overriding
• Overloading
• Function overloading
• Operator overloading

5
Array of Objects of Different Shapes
• For example, suppose a graphics program includes several different shapes: a
triangle, a ball, a square, and so on..
• Each of these classes has a member function draw() that causes the object to be
drawn on the screen.
• Now suppose the plan is to make a picture by grouping a number of these
elements together, and so that we can draw the picture in a convenient way.
• One approach is to create an array that holds pointers to all the different objects in
the picture
• shape* ptrarr[100]; // array of 100 pointers to shapes
• If you insert pointers to all the shapes into this array, you can then draw an entire
picture using a simple loop:
• for(int j=0; j<N; j++)
• ptrarr[j]->draw();

• Amaging! Each type of shape can have its own draw function that can
be invoked by its own object.

6
7
8
9
Hypothetical program!

10
Non virtual functions invoked
through pointer

11
Class Interface Diagram
ExtTime class Time class

Set Set

Increment Increment Protected data:


hrs
Write Write
mins
ExtTime Time
secs
ExtTime Time
Private data:
zone

12
class Time Specification
// SPECIFICATION FILE ( time.h)
class Time{
public :
void Set ( int h, int m, int s ) ;
void Increment ( ) ;
void Write ( ) const ;
Time ( int initH, int initM, int initS ) ; // constructor
Time (); // default constructor
protected :
int hrs ;
int mins ;
int secs ;
};

13
Class Interface Diagram
Time class

Set
Protected data:
Increment
hrs
Write
mins
Time secs

Time

14
Derived Class ExtTime
// SPECIFICATION FILE ( exttime.h)

#include “time.h”
enum ZoneType {EST, CST, MST, PST, EDT, CDT, MDT, PDT } ;

class ExtTime : public Time


// Time is the base class and use public inheritance
{
public :
void Set ( int h, int m, int s, ZoneType timeZone ) ;
void Write ( ) const; //overridden
ExtTime (int initH, int initM, int initS, ZoneType initZone ) ;
ExtTime (); // default constructor
private :
ZoneType zone ; // added data member
};
15
Class Interface Diagram
ExtTime class

Set Set

Increment Increment Protected data:


hrs
Write Write
mins
ExtTime Time
secs
ExtTime Time
Private data:
zone

16
Implementation of ExtTime

Default Constructor

ExtTime :: ExtTime ( ) ExtTime et1;


{
zone = EST ;
} et1
hrs = 0
The default constructor of mins = 0
base class, Time(), is secs = 0
automatically called, when an zone = EST
ExtTime object is created.
17
Implementation of ExtTime
Another Constructor

ExtTime :: ExtTime (int initH, int initM, int initS, ZoneType initZone)
: Time (initH, initM, initS)
// constructor initializer
{
zone = initZone ;
}

ExtTime *et2 =
5000
new ExtTime(8,30,0,EST);
hrs = 8
et2 6000 mins = 30
5000
??? secs = 0
zone = EST 18
Implementation of ExtTime
void ExtTime :: Set (int h, int m, int s, ZoneType timeZone)
{
Time :: Set (hours, minutes, seconds); // same name function call
zone = timeZone ;
}

void ExtTime :: Write ( ) const // function overriding


{
string zoneString[8] =
{“EST”, “CST”, MST”, “PST”, “EDT”, “CDT”, “MDT”, “PDT”} ;

Time :: Write ( ) ;
cout <<‘ ‘<<zoneString[zone]<<endl;
}
19
Working with ExtTime
#include “exttime.h”
……
int main()
{
ExtTime thisTime ( 8, 35, 0, PST ) ;
ExtTime thatTime ; // default constructor called
thatTime.Write( ) ; // outputs 00:00:00 EST
thatTime.Set (16, 49, 23, CDT) ;
thatTime.Write( ) ; // outputs 16:49:23 CDT
thisTime.Increment ( ) ;
thisTime.Increment ( ) ;
thisTime.Write ( ) ; // outputs 08:35:02 PST
}

20
Why Polymorphism?--Review:
Time and ExtTime Example by Inheritance
void Print (Time someTime ) //pass an object by value
{
cout << “Time is “ ;
someTime.Write ( ) ;
cout << endl ;
} // Time :: write()

CLIENT CODE
Time startTime ( 8, 30, 0 ) ; OUTPUT
ExtTime endTime (10, 45, 0, CST) ;
Time is 08:30:00
Print ( startTime ) ; Time is 10:45:00
Print ( endTime ) ;

21
Static Binding
• When the type of a formal parameter is a parent class, the argument
used can be:

the same type as the formal parameter,


or,
any derived class type.

• Static binding is the compile-time determination of which


function to call for a particular object based on the type of
the formal parameter

• When pass-by-value is used, static binding occurs

22
Can we do better?
void Print (Time someTime ) //pass an object by value
{
cout << “Time is “ ;
someTime.Write ( ) ;
cout << endl ;
} // Time :: write()

CLIENT CODE
Time startTime ( 8, 30, 0 ) ; OUTPUT
ExtTime endTime (10, 45, 0, CST) ;
Time is 08:30:00
Print ( startTime ) ; Time is 10:45:00
Print ( endTime ) ;

23
Virtual Member Function Example
• When virtual functions are used, a program that appears to be calling a function
of one class may in reality be calling a function of a different class.

// SPECIFICATION FILE ( time.h )


class Time
{
public :
. . .
virtual void Write ( ) ; // for dynamic binding
virtual ~Time(); // destructor
private :
int hrs ;
int mins ;
int secs ;
};

24
This is the way we like to see…
void Print (Time * someTime )
{
cout << “Time is “ ;
someTime->Write ( ) ;
cout << endl ;
} OUTPUT

CLIENT CODE Time is 08:30:00


Time is 10:45:00 CST
Time startTime( 8, 30, 0 ) ;
ExtTime endTime(10, 45, 0, CST) ;

Time *timeptr;
timeptr = &startTime;
Print ( timeptr ) ; Time::write()

timeptr = &endTime;
Print ( timeptr ) ; ExtTime::write()
25
Dynamic Binding
• Is the run-time determination of which function to call for a
particular object of a derived class based on the type of the
argument

• Declaring a member function to be virtual instructs the


compiler to generate code that guarantees dynamic binding

• Dynamic binding requires pass-by-reference

26
Virtual Functions (I)
• Virtual Functions overcome the problem of run time object determination
• Keyword virtual instructs the compiler to use late binding and delay the
object interpretation
• How ?
• Define a virtual function in the base class. The word virtual appears only in the
base class
• If a base class declares a virtual function, it must implement that function, even
if the body is empty
• The Virtual Attribute Is Inherited
• This means that when a derived class that has inherited a virtual function is itself
used as a base class for another derived class, the virtual function can still be
overridden.
• Virtual function in base class stays virtual in all the derived classes
• But, a derived class is not required to re-implement a virtual function. If it does
not, the base class version is used

27
Virtual Functions (II)
• Member function preceded by keyword ‘virtual’ in base
class and overridden in derived class
• Always needs to be called with base class pointer or
reference
• When base class pointer points at derived class object,
c++ determines which copy to be called depending upon
the type of the object at run time
• If object of base class invokes virtual function, then base
class implementation is invoked and if derived class
object invokes it, then derived class implementation is
invoked.
• They are resolved at run time not at compile time
Virtual Functions (III)
• General rules while defining virtual function:
1. Must be member of some class
2. Accessed using object pointers
3. Can be friend of another class
4. Signature of base class and derived class virtual
function must be identical
5. No need to use keyword ‘virtual’ in definition if its is
defined outside the class
6. Can not be a static member
7. Can not be a constructor
• Because when constructor of a class is executed there is no vtable
in the memory, means no virtual pointer defined yet.
Polymorphism Example
Virtual functions invoked through
pointer

31
Late Binding
ptr->show();
• It always compiles a call to the show() function in the base class.
• But the compiler doesn’t know what class the contents of ptr may contain.
It could be the address of an object of the Derv1 class or of the Derv2 class.
• Which version of show() does the compiler call? In fact the compiler
doesn’t know what to do, so it arranges for the decision to be deferred until
the program is running.
• At runtime, when it is known what class is pointed to by ptr, the appropriate
version of show() will be called. This is called late binding or dynamic
binding. Uses a technique called virtual table.
• Late binding requires some overhead but provides increased power and
flexibility. Because it searches the virtual table to identify right code to be
executed.
• We’ll put these ideas to use in a moment, but first let’s consider a
refinement to the idea of virtual functions.

32
Static and Dynamic binding defined
• A service can have different implementations
• Different objects
• Provides different behaviors
• Client can uniformly issue requests for the service
• The selection of code to perform a service is called
binding
• Dynamic binding -the object is identified when the
request is actually issued
• Static binding – code selection is done during code
compilation or linking
Example

Vehicle

getDesc()

Car Bus

34
Virtual Functions: Revisit
Car c(" VANITY " ,2003) ;
Vehicle * vPtr = & c;
cout<< vPtr -> getDesc () ;

• The -> notation dereferences and gets a member.


• ptr->member is equivalent to (*ptr).member.
• Because vPtr is declared as a Vehicle *, this will call the Vehicle version
of getDesc, even though the object pointed to is actually a Car.
• Usually we would want the program to select the correct function at
runtime based on which kind of object is pointed to. We can get this
behavior by adding the keyword virtual before the method definition:

1 class Vehicle {
2 ...
3 virtual const string get Desc () {...}
4 };

35
Virtual Functions: Revisit
• With this definition, the code above would correctly select the Car
version of getDesc.
• Selecting the correct function at runtime is called dynamic dispatch. This
matches the whole OOP idea – we’re sending a message to the object
and letting it figure out for itself what actions that message actually
means it should take.
• Because references are implicitly using pointers, the same issues apply
to references.

36
Pure virtual Functions
• Arguably, there is no reasonable way to define getDesc for a generic
Vehicle.
• only derived classes really need a definition of it.
• since there is no such thing as a generic vehicle that isn’t also a car,
truck, or the like.
• Still, we do want to require every derived class of Vehicle to have this
function. How do we do??
• Make virtual function as a pure virtual function.

class Vehicle {
...
virtual const string get Desc () = 0; // Pure virtual
};
• The = 0 indicates that no definition will be given. Only declared.
• It implies that one can no longer create an instance of Vehicle; one can
only create instances of Cars, Trucks, and other derived classes which do
implement the getDesc method.
• Vehicle is then an abstract class
• one which defines only an interface, but doesn’t actually implement it, and 37
therefore cannot be instantiated.
Pure virtual Functions
• It is virtual member function of base class without definition.
Should be overridden in all the derived classes
• Pure virtual function is one with the expression =0 added to the
declaration.
• Is initialized to 0. “=0” indicates that code for the function is
null pointer.
• Syntax
virtual type func-name(parameter-list) = 0;
• The equal sign here has nothing to do with assignment; the value
0 is not assigned to anything.
• The =0 syntax is simply how we tell the compiler that a virtual
function is pure.

38
Pure VirtualFunction
Example
class Shape
{
virtual void area() = 0;
};
• If derived class fails to provide definition for the
function, then it becomes an abstract class and
instance of it can not be created then.
Example: Shape yet again

Shape

virtual void draw()

Circle Rectangle

public void draw() public void draw()

40
Abstract Classes
• Some classes exist logically but not physically.
• Example : Shape
• Shape s; // Legal but silly..!! : “Shapeless shape”
• Shape makes sense only as a base of some classes derived from it. Serves as a
“category”
• Hence instantiation of such a class must be prevented

class Shape //Abstract


{ ◼ A class with one or more pure virtual
public : functions is an Abstract Class
//Pure virtual Function
◼ Objects of abstract class can’t be
virtual void draw() = 0;
created
}

Shape s; // error : variable of an abstract class


41
• A pure virtual function not defined in the derived class remains a pure
virtual function.
• Hence derived class also becomes abstract

class Circle : public Shape { //No draw() - Abstract


public :
void print(){
cout << “I am a circle” << endl;
}
class Rectangle : public Shape {
public :
void draw(){ // Override Shape::draw()
cout << “Drawing Rectangle” << endl;
}

Rectangle r; // Valid
Circle c; // error : variable of an abstract class
42
Pure virtual functions : Summary
• Pure virtual functions are useful because they make explicit the
abstractness of a class
• Tell both the user and the compiler how it was intended to be used
• Note : It is a good idea to keep the common code as close as possible to
the root of your hierarchy

43
Summary ..continued
• It is still possible to provide definition of a pure virtual function in the
base class
• The class still remains abstract and functions must be redefined in
the derived classes, but a common piece of code can be kept there to
facilitate reuse
• In this case, they can not be declared inline

class Shape { //Abstract


public : class Rectangle : public Shape
virtual void draw() = 0; {
}; public :
void draw(){
// OK, not defined inline Shape::draw(); //Reuse
void Shape::draw(){ cout <<“Rectangle”<< endl;
cout << “Shape" << endl; }
}
44
Abstract Class (I)
• It contains at least one pure virtual function
• Object of abstract class can not be created, because it
contains one or more pure virtual functions without
definition.
• A reference or pointer can be created to support run
time polymorphism
• All the pure virtual functions of abstract class must be
overridden in derived class.
• Can be used to create generic, extensible libraries for
programmer to use in their own implementations
Abstract Class (II)
Example of abstract class. Similarly, another sub class
Triangle can also be added.
Virtual Destructors
• Derived classes are often handled via base class references, declaring a
non-virtual destructor will be dispatched statically, obfuscating the
destructor of the derived class.
• Suppose you use delete with a base class pointer to a derived class
object to destroy the derived-class object. If the base-class destructor is
not virtual then delete, like a normal member function, calls the
destructor for the base class, not the destructor for the derived class.
This will cause only the base part of the object to be destroyed.
• It is always a good idea to make destructors of base classes virtual.

47
class Base
{
public:
~Base()
{
std::cout << "Destroying base" << std::endl;
} int main()
}; {
Base* p = new Derived(5);
class Derived : public Base
{
delete p;
public: }
Derived(int number) This will output:
{ > Destroying base
some_resource_ = new int(number);
}
Making Base’s destructor virtual will
~Derived() result in the expected behaviour:
{
std::cout << "Destroying derived" << std::endl;
delete some_resource_;
> Destroying derived
} > Destroying base

private:
int* some_resource_;
};

48
Revisit: Hybrid Inheritance

49
Example: Hybrid Inheritance
Parent

basedata

Child1 Child2

GrandChild

getdata()

50
Example code: Hybrid Inheritance
// ambiguous reference to base class
class Parent
{
protected:
int basedata;
};
class Child1 : public Parent
{ };
class Child2 : public Parent
{ };
class Grandchild : public Child1, public Child2
{
public:
int getdata()
{ return basedata; } // ERROR: ambiguous
};

51
Ambiguity!
• Consider the situation shown in Figure, with a base class, Parent; two
derived classes, Child1 and Child2; and a fourth class, GrandChild,
derived from both Child1 and Child2.
• In this arrangement a problem can arise if a member function in the
Grandchild class wants to access data or functions in the Parent class.
• A compiler error occurs when the getdata() member function in
Grandchild attempts to access basedata in Parent.
• Why? When the Child1 and Child2 classes are derived from Parent,
each inherits a copy of Parent; this copy is called a subobject. Each of
the two subobjects contains its own copy of Parent’s data, including
basedata.
• Now, when Grandchild refers to basedata, which of the two copies
will it access? The situation is ambiguous, and that’s what the
compiler reports.

52
Virtual base classes
• Virtual base classes are relate to multiple inheritance.
• To eliminate the ambiguity, we make Child1 and Child2 into virtual base classes

// virtual base classes


class Parent
{
protected:
int basedata;
};
class Child1 : virtual public Parent // shares copy of Parent
{ };
class Child2 : virtual public Parent // shares copy of Parent
{ };
class Grandchild : public Child1, public Child2
{
public:
int getdata()
{ return basedata; } // OK: only one copy of Parent
};
53
Virtual base classes
• The use of the keyword virtual in these two classes causes them to
share a single common subobject of their base class Parent.
• Since there is only one copy of basedata, there is no ambiguity when
it is referred to in Grandchild.
• The need for virtual base classes may indicate a conceptual problem
with the use of multiple inheritance, so they should be used with
caution.

• Inheritance – Basic Concepts


• Class Hierarchy
• Code Reuse, Easy to maintain
• Type of inheritance : public, private, protected, virtual
• …

54
Accessing the class size
#include <iostream>
using namespace std;

class NonVClass {
int x=10;
public:
void foo() {}
};

class VClass {
int y=20;
float z=30.5;
public:
void foo() {}
};
int main() {
cout << "Size of NonVClass: " << sizeof(NonVClass) << endl;
cout << "Size of VClass: " << sizeof(VClass) << endl;
}
55
Accessing the class size
#include <iostream>
using namespace std;

class NonVClass {
public:
void foo() {}
};

class VClass {
public:
void foo() {}
};
int main() {
cout << "Size of NonVClass: " << sizeof(NonVClass) << endl;
cout << "Size of VClass: " << sizeof(VClass) << endl;
}

56
Accessing the class size
#include <iostream>
using namespace std;

class NonVirtualClass {
public:
void foo() {}
};

class VirtualClass {
public:
virtual void foo() {}
};
int main() {
cout << "Size of NonVirtualClass: " << sizeof(NonVirtualClass) << endl;
cout << "Size of VirtualClass: " << sizeof(VirtualClass) << endl;
}

57
Accessing the class size
#include <iostream>
using namespace std;

class NonVirtualClass {
public: Output:
void foo() {} Size of NonVirtualClass: 1
}; Size of VirtualClass: 8

class VirtualClass {
public:
virtual void foo() {}
};
int main() {
cout << "Size of NonVirtualClass: " << sizeof(NonVirtualClass) << endl;
cout << "Size of VirtualClass: " << sizeof(VirtualClass) << endl;
}
• NonVirtualClass has a size of 1 because in C++ classes can’t have zero size.
• VirtualClass’s size is 8 on a 64 bit machine. Why? Because there’s a hidden
pointer inside it pointing to a vtable.
58
Virtual Tables
• Virtual functions in C++, are implemented using the concept
of virtual tables (vtable) to achieve polymorphism.
• Vtable:
• Whenever a class itself contains virtual functions or overrides virtual
functions from a parent class the compiler builds a vtable for that
class.
• Not all classes have a vtable created for them by the compiler.
• The vtable contains function pointers that point to the virtual
functions in that class.
• There can only be one vtable per class
• All objects of the same class will share the same vtable
• The layout is generally compiler-specific and (somewhat) stable

59
int main()
class base { { base* p;
public: derived obj1;
void fun_1() { cout << "base-1\n"; } p = &obj1;
virtual void fun_2() { cout << "base-2\n"; } // Early binding because fun1() is non-virtual
virtual void fun_3() { cout << "base-3\n"; } // in base
virtual void fun_4() { cout << "base-4\n"; } p->fun_1();
}; // Late binding
class derived : public base { p->fun_2();
public: // Late binding
void fun_1() { cout << "derived-1\n"; } p->fun_3();
void fun_2() { cout << "derived-2\n"; } // Late binding
void fun_4(int x) { cout << "derived-4\n"; } p->fun_4();
}; // Early binding but this function call is
//illegal(produces error) because pointer is of
//base type and function is of derived class
// p->fun_4(5);
}
60
Output:
base-1
derived-2
base-3
base-4

61
int main()
class base { { base* p;
public: derived obj1;
void fun_1() { cout << "base-1\n"; } p = &obj1;
virtual void fun_2() { cout << "base-2\n"; } // Early binding because fun1() is non-virtual
virtual void fun_3() { cout << "base-3\n"; } // in base
virtual void fun_4() { cout << "base-4\n"; } p->fun_1();
}; // Late binding
class derived : public base { p->fun_2();
public: // Late binding
void fun_1() { cout << "derived-1\n"; } p->fun_3();
void fun_2() { cout << "derived-2\n"; } // Late binding
void fun_4(int x) { cout << "derived-4\n"; } p->fun_4();
}; // Early binding but this function call is
//illegal(produces error) becasue pointer is of
//base type and function is of derived class
p->fun_4(5);
}
62
Example
class B
{
public:
virtual void bar();
virtual void quick();
};
void B::bar()
{ std::cout << "This is B's implementation of bar" << std::endl; }

void B::quick()
{ std::cout << "This is B's implementation of quck" << std::endl; }

class C : public B
{
public:
void bar() override;
};
void C::bar()
{
std::cout << "This is C's implementation of bar" << std::endl;
}

63
Challenge
• Now consider the following call to bar():

B* b = new C();
b->bar();

• If we use static dispatch as above, the call b->bar() would execute


B::bar(), since b points to an object of type B. This would be wrong,
because b actually points to an object of type C and C::bar() should
be called instead.
• Problem: given that virtual functions can be redefined in subclasses,
calls via pointers (or references) to a base type can not be dispatched
at compile time. The compiler has to find the right function definition
(i.e. the most specific one) at runtime.
• This process is called dynamic dispatch or late method binding.

64
Example: Dynamic Dispatch - Virtual Tables

• The vtable contains an entry for each virtual function accessible by the
class and stores a pointer to its definition.
• Entries in the vtable can point to either functions declared in the class
itself (e.g. C::bar()), or virtual functions inherited from a base class (e.g.
C::qux()).
65
• The vtable of class B has two entries, one for each of the two
virtual functions declared in B’s scope: bar() and qux().
Additionally, the vtable of B points to the local definition of
functions, since they are the most specific (and only) from
B’s point of view.
• More interesting is C’s vtable. In this case, the entry for bar()
points to own C’s implementation, given that it is more
specific than B::bar(). Since C doesn’t override qux(), its
entry in the vtable points to B’s definition (the most specific
definition).
• Note that vtables exist at the class level, meaning there
exists a single vtable per class, and is shared by all instances.

66
• You might be thinking: vtables are cool and all, but how
exactly do they solve the problem of dynamic dispatch?
• When the compiler sees b->bar() in the example above, it
will lookup B’s vtable for bar’s entry and follow the
corresponding function pointer, right? We would still be
calling B::bar() and not C::bar()…

• Very true, the second part of the story: vpointers.


• Every time the compiler creates a vtable for a class, it adds an
extra argument to it: a pointer to the corresponding virtual table,
called the vpointer.

67
• Note that the vpointer is just another class member added by the
compiler and increases the size of every object that has a vtable by
sizeof(vpointer)
• when a call to a virtual function on an object is performed, the
vpointer of the object is used to find the corresponding vtable of the
class.
• Next, the function name is used as index to the vtable to find the
correct (most specific) routine to be executed.

68
• Hopefully you have grasped how dynamic function dispatch can be
implemented by using vtables:
1. when a call to a virtual function on an object is performed, the vpointer of
the object is used to find the corresponding vtable of the class.
2. Next, the function name is used as index to the vtable to find the correct
(most specific) routine to be executed. Done!

69
class shape { Obj_Shape
public:
shape(); // constructor position
virtual double area() const;
virtual double perimeter() const;
outline
~~~
private:
coordinates position; fill
color outline, fill;
};

70
Code segment

Shape Shape vtpl


vptr Shape::area

position Shape::perimeter

outline

fill

71
class circle: public shape {
public:
circle(double r); // constructor circle circle vtpl
virtual double area() const;
vptr circle::area
virtual double perimeter() const;
~~~
position circle::perimeter
private:
double radius; outline
};
fill Base class (Shape) subobject

radius

72
class rectangle: public shape { rectangle
rectangle vtpl
public:
rectangle(double h, double w); vptr rectangle::area
virtual double area() const;
position rectangle::perimeter
virtual double perimeter() const;
~~~
outline
private:
double height, width; Base class (Shape) subobject
fill
};
height

width
Obj 1
vptr
position
Code segment
outline Shape vtpl
fill
Pointer to Shape::area
Obj 2 area() code
vptr
position Pointer to Shape::perimeter
perimeter() code
outline
fill

Obj n
vptr
position
outline
fill 74
This pointer
• Every object in C++ has access to its own address through an
important pointer called this pointer.
• i.e. this is a keyword that refers to the current instance of the class
• this pointer is an implicit parameter to all member functions.
• Therefore, inside a member function, this may be used to refer to the
invoking object. (Can't be used in static member functions! Why?)
• Only member functions have a this pointer.
• Friend functions do not have a this pointer, because friends are not
members of a class.
• Uses
• It can be used to pass current object as a parameter to another method.
• It can be used to refer current class instance variable.
• It can be used to declare indexers.

75
class Employee {
public:
int main(void) {
int id; //data member (also instance variable)
Employee e1 =Employee(101, “Somu",
string name; //data member(also instance variable)
890000); //creating an object of Employee
float salary;
Employee e2=Employee(102, "Nakul",
Employee(int id, string name, float salary) 59000); //creating an object of Employee
{ e1.display();
this->id = id; e2.display();
this->name = name; return 0;
this->salary = salary; }
}
void display()
{
cout<<id<<" "<<name<<" "<<salary<<endl;
}
};

76
class Box {
private: int main(void) {
Box Box1(3.3, 1.2, 1.5); // Declare box1
double length; // Length of a box
Box Box2(8.5, 6.0, 2.0); // Declare box2
double breadth; // Breadth of a box
double height; // Height of a box if(Box1.compare(Box2)) {
cout << "Box2 is smaller than Box1"
public:
<<endl;
// Constructor definition } else {
Box(double l = 2.0, double b = 2.0, double h = 2.0) { cout << "Box2 is equal to or larger than
Box1" <<endl;
cout <<"Constructor called." << endl;
}
length = l; breadth = b; height = h;
} return 0;
double Volume() { }

return length * breadth * height;


}
int compare(Box box) { Output:
return this->Volume() > box.Volume(); Constructor called.
Constructor called.
} Box2 is equal to or larger than Box1
};
#include <iostream> class Stringed : public Instrument {
using namespace std; public: void play(note) const {
enum note { middleC, Csharp, Cflat }; // Etc. cout << "Stringed::play" << endl;
class Instrument { }
public: virtual void play(note) const { char* what() const { return "Stringed"; }
cout << "Instrument::play" << endl; void adjust(int) {}
} };
virtual char* what() const { class Brass : public Wind {
return "Instrument"; public: void play(note) const {
} cout << "Brass::play" << endl;
// Assume this will modify the object: }
virtual void adjust(int) {} char* what() const { return "Brass"; }
}; };
class Wind : public Instrument { class Woodwind : public Wind {
public: void play(note) const { public: void play(note) const {
cout << "Wind::play" << endl; cout << "Woodwind::play" << endl;
} }
char* what() const { return "Wind"; } char* what() const { return "Woodwind"; }
void adjust(int) {} };
}; // Identical function from before:
class Percussion : public Instrument { void tune(Instrument& i) {
public: // ...
void play(note) const { i.play(middleC);
cout << "Percussion::play" << endl; }
}
char* what() const { return "Percussion"; }
void adjust(int) {} 78
// New function: int main() {
void f(Instrument& i) { i.adjust(1); } Wind flute;
Percussion drum;
Stringed violin;
// Upcasting during array initialization: Brass flugelhorn;
Instrument* A[] = { Woodwind recorder;
tune(flute);
new Wind,
tune(drum);
new Percussion, tune(violin);
new Stringed, tune(flugelhorn);
new Brass, tune(recorder);
f(flugelhorn);
}; }

79
80
81
82
Interface
• All functions are pure virtual functions
• No instantiation only for interface referencing

83
Inheritance Vs Composition
• Object composition should be favored than
inheritance
• Composition to flexible doesn’t break encapsulation
• Using Composition it is easy to change objects than super
class code
• Composition promotes smaller, more focused classes and
smaller inheritance hierarchies
• Focus is one task to one class
• Use inheritance to support type, dynamic binding
and polymorphism
Abstract classes Vs Interfaces
• Both mechanisms define required behavior that another class must
implement
• Interfaces allow interface inheritance
• Classes allow implementation inheritance
• Interfaces are limited to public methods and constants with no
implementation allowed
• Classes can have static methods, protected parts and partial
implementation
Abstract classes Vs Interfaces
• Abstract class is easier to evolve over time
• Adding a method that is partial implementation so that the
subclasses do not need to provide their own implementation
unless they want to override the default version
• Adding the functionality will invalidate all the classes that use this
interface
• Classes can allow mutable data field but not interfaces
Abstract classes Vs Interfaces
abstract class time {
public: int getMinutes() = 0;
}
Class days: public time{
private: int days;
public: int getMinutes() { returns days*24*60;
}}
Class hoursMinutes: publictime {
private: int hours;
int minutes;
public: int getMinutes(){ return hours*60+minutes;}}
Abstract classes Vs Interfaces
Interface time{
int getMinutes()=0;}
Class days: public time{
private: int days;
public: int getMinutes(){ returns days*24*60;
}}
Class hoursMinutes: publictime{
Private: int hours;
int minutes;
Public: int getMinutes() {
Returns hours*60+minutes;
}}
How to implement getSeconds()

• In abstract class add the following method


public: int getSeconds() {
return getMinutes()*60; }
• Modified interface
interface time {
int getMinutes()=0;
int getSeconds()=0; }
Guidelines

• In case you get the interface right the first time,


interfaces tend to be a better choice than abstract
classes.
• Abstract classes are useful when a partial
implementation is required
• You should also define interface and implement in
abstract class ☺
Inheritance Vs Delegation
• Use Inheritance
• Is-a relationship exists
• Static relationship - does not change over a time
• No Hiding of a variable(s) and method(s)
• Use delegation
• Is-a-role-played-by
• Reuse and extend the behavior of a class
• Allows behavior to be easily composed at runtime
• Less convenient than inheritance – as it requires more
code to implement
• Other disadvantage is less structured than inheritance
Types of Polymorphism

• Polymorphic
• Values, functions and variables are of more than one type
• Varieties of polymorphism
• Universal polymorphism
• Parametric polymorphism
• Inclusion polymorphism
• Ad hoc polymorphism
• Overloading
• coercion
Polymorphism contd..
• Parametric polymorphism - function works
uniformly on a range of types
• the function has explicit or implicit type parameter which
determines the type of the argument for each application of that
function
• Inclusion polymorphism - object is viewed as
belonging to many different classes that need not
be disjoint.
• Subtyping is an instance of inclusion polymorphism
• Maruthi is a vehicle
Polymorphism contd..

• Overloading is a convenient syntactic abbreviation


as it is different names to the different functions
• Coercion is a semantic operation that is needed to
convert an argument to the type expected by a
function
• Value sharing is a special form of parametric
polymorphism
• Ex.. Nil in Pascal
Parametric Vs Ad hoc polymorphism
Parametric Ad hoc polymorphism
• Method works • Method appears to
work on several
uniformly on a range of different types (finite
types (infinite types) and unrelated
• Exhibit some common (potentially) types)
structure • Many not exhibit a
common structure
• Behaves similarly • May behave in
unrelated ways for each
type
• Executes same code • Execute different code
Polymorphism Summary:
• When you use virtual functions, compiler store additional information
about the types of object available and created
• Polymorphism is supported at the additional overhead
• Important :
• virtual functions work only with pointers/references
• Not with objects even if the function is virtual
• If a class declares any virtual methods, the destructor of the class should be
declared as virtual as well.

96
Conclusions
• Polymorphism is built upon class inheritance

• It allows different versions of a function to be called in the same


manner, with some overhead

• Polymorphism is implemented with virtual functions, and requires pass-


by-reference

97

You might also like