PPL Chapter 12
PPL Chapter 12
Programming Languages
Dr. R. Bala Krishnan
Asst. Prof.
Dept. of CSE
NIT, Trichy – 620 015
Ph: 999 470 4853 E-Mail: balakrishnan@nitt.edu
Books
• Text Books
✓ Robert W. Sebesta, “Concepts of Programming Languages”, Tenth
Edition, Addison Wesley, 2012.
✓ Michael L. Scott, “Programming Language Pragmatics”, Third Edition,
Morgan Kaufmann, 2009.
• Reference Books
✓ Allen B Tucker, and Robert E Noonan, “Programming Languages –
Principles and Paradigms”, Second Edition, Tata McGraw Hill, 2007.
✓ R. Kent Dybvig, “The Scheme Programming Language”, Fourth
Edition, MIT Press, 2009.
✓ Jeffrey D. Ullman, “Elements of ML Programming”, Second Edition,
Prentice Hall, 1998.
✓ Richard A. O'Keefe, “The Craft of Prolog”, MIT Press, 2009.
✓ W. F. Clocksin, C. S. Mellish, “Programming in Prolog: Using the ISO
Standard”, Fifth Edition, Springer, 2003.
2
Chapters
Chapter No. Title
1. Preliminaries
2. Evolution of the Major Programming Languages
3. Describing Syntax and Semantics
4. Lexical and Syntax Analysis
5. Names, Binding, Type Checking and Scopes
6. Data Types
7. Expressions and Assignment Statements
8. Statement-Level Control Structures
9. Subprograms
10. Implementing Subprograms
11. Abstract Data Types and Encapsulation Constructs
12. Support for Object-Oriented Programming
13. Concurrency
14. Exception Handling and Event Handling
15. Functional Programming Languages
3
16. Logic Programming Languages
Chapter 12 – Support for Object-
Oriented Programming
4
Objectives
• Introduction to object-oriented programming
5
Micsellaneous
Object-Oriented Programming Concepts
• Encapsulation
• Inheritance
6
Miscellaneous
#include<iostream> class Add
function add(int c, int d) using namespace std; {
{ class Add protected:
return (c + d); { int num1, num2;
public: int sum(int n1, int n2)
}
int num1, num2; {
int sum(int n1, int n2) return n1 + n2;
void main() { }
{ return n1+n2; };
} int main()
int a = 5, b = 10;
}; {
printf(“%d”, add(a, b)); int main() //Creating object of class
} { Add obj;
//Creating object of class obj.num1 = 5;
Add obj; obj.num2 = 10;
O/P: 15 obj.num1 = 5; cout << obj.sum(obj.num1,
obj.num2 = 10; obj.num2);
cout << obj.sum(obj.num1, }
obj.num2);
}
O/P: 15 O/P: Error 7
Miscellaneous
class construct class Point int main()
{ { {
public: private: // Constructor called
int x, y; Point p1(10, 15);
int a, b;
public:
construct() Point(int x1, int y1) // Access values
{ { assigned by Constructor
a = 10; x = x1; cout << "p1.x = " <<
b = 20; y = y1; p1.getX() << ", p1.y = " <<
} } p1.getY();
};
int getX() return 0;
int main() { }
{ return x;
// Default constructor called }
automatically when the object is int getY()
created { O/P: p1.x = 10, p1.y = 15
construct c; return y;
cout << "a: " << c.a << endl }
<< "b: " << c.b; };
Types
return 1; • Default Constructor
} O/P: a: 10 b: 20 • Parameterized Constructor 8
Miscellaneous
class HelloWorld int main()
{ {
Destructor
public: HelloWorld obj;
HelloWorld() obj.display();
{ return 0;
cout<<"Constructor is called"<<endl; }
}
~HelloWorld()
{ A destructor is automatically called when:
1) The program finished execution
cout<<"Destructor is called"<<endl;
2) When a scope (the { } parenthesis)
} containing local variable ends
void display() 3) When you call the delete operator
{
cout<<"Hello World!"<<endl; O/P: Constructor is called
} Hello World!
Destructor is called
};
9
Miscellaneous
Access Specifiers
10
Miscellaneous
class Add
{
public: Instance
int num1, num2; Variables
Local Variable called
static int key; // Default value = 0 c=0
from obj1 (sum)
int sum(int n1, int n2) Static or
{ num2 = 15
Class Instance
int c = 0; Variable Variable (obj1) num1 = 10
return n1 + n2;
} Local
Variable num2 = 10
} Instance
int main() Variable (obj) num1 = 5
{
Static or Class
//Creating object of class key = 15
Variable (Add)
Add obj, obj1;
obj.num1 = 5; obj1.num1 = 10;
Memory
obj.num2 = 10; obj1.num2 = 15;
cout << obj1.sum(num1, num2);
}
int Add::key = 15; 11
Miscellaneous
Inheritance -> Is
//Base class int main() Unidirectional
class Parent {
Types
{ Child obj1; • Single Inheritance
public: obj1.id_c = 7; • Multiple Inheritance
int id_p; obj1.id_p = 91;
}; cout << "Child id is " << obj1.id_c <<
endl;
class Child : public Parent cout << "Parent id is " << obj1.id_p <<
{ endl;
public:
int id_c; return 0;
}; }
O/P: Child id is 7
Parent id is 91
12
Miscellaneous
class Vehicle class Car: public Vehicle, public
{ FourWheeler {
public: Inheritance
Vehicle() };
Types
{
• Single Inheritance
cout << "This is a Vehicle" << endl; int main() • Multiple Inheritance
} {
}; // creating object of sub class will
// invoke the constructor of base classes
class FourWheeler Car obj;
{ return 0;
public: }
FourWheeler()
{
cout << "This is a 4 wheeler Vehicle"
<< endl;
} O/P: This is a Vehicle
}; This is a 4 wheeler Vehicle
13
Miscellaneous
class Vehicle class Car: public Vehicle, public
{ FourWheeler { Inheritance
public: public: Types
Vehicle() Car() • Single Inheritance
{ { • Multiple Inheritance
cout << "This is a Vehicle" << endl; cout << "This is a Car" << endl;
} }
}; };
15
Miscellaneous
class Geeks int main()
{ {
public:
Polymorphism
Geeks obj1;
void func(int x)
{ obj1.func(7);
cout << "value of x is " << x << obj1.func(9.132);
endl; obj1.func(85, 64);
} return 0;
}
void func(double x)
{
cout << "value of x is " << x << When there are multiple functions with same
endl; name but different parameters then these
} functions are said to be overloaded. Functions
can be overloaded by change in number of
void func(int x, int y) arguments or/and change in type of arguments
{
cout << "value of x and y is " << x Types
<< ", " << y << endl; • Functional Overloading (Compile Time)
}
• Operator Overloading (Compile Time)
};
• Virtual Functions (Run Time)
16
Miscellaneous
• Function Overloading (achieved at
compile time)
Function Overloading vs
- Provides multiple definitions of the Function Overriding
function by changing signature
- That is, changing number of Example:
parameters, change datatype of Class a
parameters (Return type doesn’t {
play any role) public: virtual void display()
- It can be done in base as well as {
derived class cout << "hello";
Example: }
void area(int a); };
void area(int a, int b); Class b:public a
• Function Overriding (achieved at run {
time) public: void display()
- Redefinition of base class function {
in its derived class with same cout << "bye";
signature }
- That is, return type and parameters https://www.geeksforgeeks.org/function-
};
- It can only be done in derived class overloading-vs-function-overriding-in-cpp/
17
Miscellaneous
class Complex int main()
{
private: {
int real, imag; Complex c1(10, 5), c2(2, 4);
public: Complex c3 = c1 + c2; // An example
Complex(int r = 0, int i =0)
{
call to "operator+"
real = r; c3.print();
imag = i; }
}
Complex operator + (Complex const
&obj)
{ “+” -> Addition (Two Integers),
Complex res; Concatenation (Strings), Addition
res.real = real + obj.real; (Complex Numbers)
res.imag = imag + obj.imag;
return res;
} Types
void print() • Functional Overloading (Compile Time)
{ • Operator Overloading (Compile Time)
cout << real << " + i" << imag << endl; • Virtual Functions (Run Time)
}
};
18
Miscellaneous
class base int main()
{ { https://hownot2code.com/2017/0
public: 8/10/c-pointers-why-we-need-
virtual void print () base *bptr;
{ derived d; them-when-we-use-them-how-
cout<< "print base class" <<endl; they-differ-from-accessing-to-
} bptr = &d;
object-itself/
void show () //virtual function, binded at runtime (Runtime
{
cout<< "show base class" <<endl; polymorphism)
} bptr->print();
};
class derived: public base // Non-virtual function, binded at compile time
{ bptr->show();
public: This type of polymorphism is achieved
void print () //print () is already virtual
function in derived class, we could also by Function Overriding. Function
return 0;
declared as virtual void print () explicitly overriding occurs when a derived class
{ } has a definition for one of the member
cout<< "print derived class" <<endl; functions of the base class. That base
}
function is said to be overridden
void show ()
{ Types
cout<< "show derived class" <<endl; • Functional Overloading (Compile Time)
}
}; O/P: print derived class • Operator Overloading (Compile Time)
show base class • Virtual Functions (Run Time) 19
Miscellaneous
class base int main()
{ {
public:
void print () base *bptr;
{ derived d;
cout<< "print base class" <<endl; bptr = &d;
}
void show () //Non-virtual function, binded at compile time
{ bptr->print();
cout<< "show base class" <<endl;
}
}; // Non-virtual function, binded at compile time
bptr->show();
class derived: public base
{
public: return 0; Note: “Virtual” keyword is
void print () } not used. Hence, objects
{ are binded at compile time
cout<< "print derived class" <<endl;
} itself
void show ()
{
cout<< "show derived class" <<endl;
} O/P: print base class
}; show base class
20
Miscellaneous
class base int main()
{ {
public:
void print () base bptr;
{ bptr.print();
cout<< "print base class" <<endl; bptr.show(); Note: Individual objects are
} created
derived d;
void show () d.print();
{ d.show();
cout<< "show base class" <<endl;
}
}; return 0;
}
class derived: public base
{
public:
void print ()
{
cout<< "print derived class" <<endl;
} O/P: print base class
void show () show base class
{ print derived class
cout<< "show derived class" <<endl; show derived class
}
};
21
Miscellaneous
class base int main()
{ {
public:
virtual void print () base bptr; Note: In the case of individual
{ bptr.print(); objects, there is no effect even
cout<< "print base class" <<endl; though virtual keyword is
} bptr.show();
derived d; added
void show () d.print();
{
cout<< "show base class" <<endl; d.show();
}
};
return 0;
class derived: public base }
{
public:
void print () //print () is already virtual
function in derived class, we could also
declared as virtual void print () explicitly
{
cout<< "print derived class" <<endl; O/P: print base class
}
show base class
void show () print derived class
{
cout<< "show derived class" <<endl; show derived class
}
};
22
Miscellaneous
class Base
{ Abstract Method or Pure class Test Abstract Class (Interface) or
int x; Virtual Method in C++ { Abstract Base Class in C++
public:
virtual void fun() = 0; // Pure Virtual Function
int x;
int getX() { return x; } public:
}; virtual void show() = 0;
int getX() { return x; }
// This class inherits from Base and implements
fun() }; Such a class usually cannot be
class Derived: public Base instantiated, because some of
{ its methods are declared but
int main(void)
int y; are not defined (they do not
public: { have bodies). Any subclass of
void fun() Test t; an abstract class that is to be
{ return 0; instantiated must provide
cout << "fun() called"; implementations (definitions)
} }
of all of the inherited abstract
}; methods.
int main(void)
{ O/P: Compiler Error: cannot declare
Derived d; variable 't' to be of abstract type 'Test'
d.fun(); O/P: fun() called because the following virtual functions
return 0; are pure within 'Test': note: virtual void
} Test::show() 23
Miscellaneous
class Base Class Derived_1: public Derived
{ {
int x; int z:
public:
public: virtual void fun()
virtual void fun() = 0; //Pure Virtual Function {
virtual void fun1() = 0; // Pure Virtual Function cout << “Show”;
}
int getX() virtual void fun1()
{ {
return x; cout << “Show_1”;
} }
virtual void fun2()
}; {
cout << “Show_2”;
class Derived: public Base }
};
{
int y; int main(void)
public: {
Base b; // Throws Error
virtual void fun() = 0; Derived d; // Throws Error
virtual void fun1() = 0; Derived_1 d;
virtual void fun2() = 0; d.fun();
return 0;
}; } O/P: Show
24
Miscellaneous
class MyClass { // The class
public: // Access specifier
void myMethod(); // Method/function declaration
};
int main() {
MyClass myObj; // Create an object of MyClass
myObj.myMethod(); // Call the method
return 0;
}
25
Miscellaneous
Single Inheritance Multiple Inheritance
Multi-Level Inheritance
Hierarchical Inheritance
26
Miscellaneous
Hybrid (Virtual) Inheritance
27
Miscellaneous
class Node class Node
{ Friend Class { Friend Function
private: private:
int key; int key;
Node* next; Node* next;
/* Other members of Node Class */
/* Other members of Node Class */
friend class LinkedList;
// Now class LinkedList can friend int LinkedList::search();
// access private members of Node
}; // Only search() of linkedList
// can access internal members
Class LinkedList };
{
public: • A friend class can access private and protected members of other
int search() class in which it is declared as friend. It is sometimes useful to
{ allow a particular class to access private members of other class
….. • Like friend class, a friend function can be given special grant to
} access private and protected members. A friend function can be:
}; a) A method of another class
28
b) A global function
Miscellaneous
class base
{
class derived: public base
{
public:
base()
public: Destructor
derived()
{ {
cout << "Base Class Constructor Called" cout << "Dervied Class Destructor
<< endl; Called" << endl;
} }
void print () void print ()
{ {
cout<< "print base class" <<endl; cout<< "print derived class" <<endl;
} }
void show () void show ()
{ {
cout<< "show base class" <<endl; cout<< "show derived class" <<endl;
} }
~base() ~derived()
{
{
cout << "Derived Class Destructor
cout << "Base Class Destructor Called" Called" << endl;
<< endl; }
} };
};
https://hownot2code.com/2017/08/10/c-pointers-why-we-need-them-
29
when-we-use-them-how-they-differ-from-accessing-to-object-itself/
Miscellaneous
int main()
int main()
{ {
base bptr; base *bptr; Destructor
bptr.print(); derived d;
bptr.show(); bptr = &d;
derived d; bptr->print();
d.print(); bptr->show();
d.show(); cout << "1" << endl;
cout << "1" <<endl; return 0;
return 0; }
cout << "2" << endl;
}
O/P: Base Class Constructor Called
print base class O/P: Base Class Constructor Called
show base class Derived Class Constructor Called
Base Class Constructor Called print base class
Derived Class Constructor Called show base class
print derived class 1
show derived class Derived Class Destructor Called
1 Base Class Destructor Called
Object “d” Derived Class Destructor Called
deleted Base Class Destructor Called Object “bptr” 30
Base Class Destructor Called deleted
Miscellaneous
int main() int main() Destructor
{ {
base *bptr1 = new base(); base *bptr1 = new base();
base *bptr; delete bptr1; Note: Whenever you
derived d; base *bptr; create an object in
bptr = &d; derived d; heap memory using
bptr->print(); bptr = &d; “new” keyword, you
bptr->show(); bptr->print(); have to delete it
cout << "1" << endl; bptr->show(); explicitly using
return 0; cout << "1" << endl; “delete” keyword.
} return 0; Here, object “bptr1” is
} deleted explicitly
O/P: Base Class Constructor Called
Base Class Constructor Called O/P: Base Class Constructor Called Object
Derived Class Constructor Called Base Class Destructor Called “bptr1”
print base class Base Class Constructor Called deleted
show base class Derived Class Constructor Called
1 print base class
Object “d” Derived Class Destructor Called
show base class
deleted Base Class Destructor Called
1
Object “d” Derived Class Destructor Called
Note: Object “bptr1” is deleted
Base Class Destructor Called 31
not deleted
Miscellaneous
int main()
{
base *bptr1;
bptr1->print();
bptr1->show();
cout << "1" << endl;
return 0;
}
43
Dynamic Binding
car
• Void Display()
- Button
• Void click()
50
Miscellaneous
• In OOP, IS-A relationship is completely inheritance
• This means, that the child class is a type of parent class. Eg: An apple is a
fruit. So you will extend fruit to get apple
• Composition means creating instances which have references to other
objects
• Eg: A room has a table. So you will create a class room and then in that
class create an instance of type table
57
Design Issues for Object-Oriented
Languages
Allocation and Deallocation of Objects
• Two design questions concerning the allocation and deallocation of
objects
- First question is the place from which objects are allocated
▪ If they behave like the abstract data types, then perhaps they
can be allocated from anywhere
❑ This means they could be allocated from the run-time
stack or explicitly created on the heap with an operator
or function, such as new
▪ If they are all heap dynamic, there is the advantage of having a
uniform method of creation and access through pointer or
reference variables
❑ This design simplifies the assignment operation for
objects, making it in all cases only a pointer or reference
value change
❑ Also allows references to objects to be implicitly
dereferenced, simplifying the access syntax
58
Design Issues for Object-Oriented
Languages
▪ If objects are stack dynamic (value variables), there is a
problem with regard to subtypes
❑ If class B is a child of class A and B is a subtype of A,
then an object of B type can be assigned to a
variable of A type
❑ Eg: If b1 is a variable of B type and a1 is a variable of
A type, then a1 = b1; is a legal statement
❑ If a1 and b1 are references to heap-dynamic objects,
there is no problem—the assignment is a simple
pointer assignment
❑ However, if a1 and b1 are stack dynamic, then they
are value variables and, if assigned the value of the
object, must be copied to the space of the target
object
❑ If B adds a data field to what it inherited from A,
then a1 will not have sufficient space on the stack
for all of b1
❑ The excess will simply be truncated, which could be
confusing to programmers who write or use the
code
❑ This truncation is called object slicing 59
Design Issues for Object-Oriented
Languages
- Second question here is concerned with those cases where objects are
allocated from the heap
▪ Question is whether deallocation is implicit, explicit, or both
❑ If deallocation is implicit, some implicit method of storage
reclamation is required
❑ If deallocation can be explicit, that raises the issue of
whether dangling pointers or references can be created
Dynamic and Static Binding
• Dynamic binding of messages to methods is an essential part of object-
oriented programming
• Question here is whether all binding of messages to methods is dynamic
• Alternative is to allow the user to specify whether a specific binding is to
be dynamic or static
• Advantage of this is that static bindings are faster
• So, if a binding need not be dynamic, why pay the price?
60
Design Issues for Object-Oriented
Languages
Nested Classes Class A Nesting
• One of the primary motivations for nesting class { Class
definitions is information hiding public:
int a = 5;
• If a new class is needed by only one class, there is no
void display()
reason to define it so it can be seen by other classes {
- New class can be nested inside the class that uses printf(“Show”);
it }
- In some cases, the new class is nested inside a Class B
subprogram, rather than directly in another class { Nested
public: Class
- The class in which the new class is nested is called
int b = 10;
the nesting class public int calc(int a,
• Most obvious design issues associated with class nesting int b)
are related to visibility {
• Specifically, one issue is: Which of the facilities of the return (a + b);
nesting class are visible in the nested class }
}
• The other main issue is the opposite: Which of the
}
facilities of the nested class are visible in the nesting class? 61
Design Issues for Object-Oriented
Languages
Initialization of Objects
62
Support for Object-Oriented
Programming in C++
• C++ was the first widely used object-oriented programming language and
is still among the most popular
• So, naturally, it is the one with which other languages are often compared
General Characteristics
• To main backward compatibility with C, C++ retains the type system of C
and adds classes to it
• C++ has both traditional imperative-language types and the class structure
of an object-oriented language
• C++ is a hybrid language, supporting both procedural programming and
object- oriented programming
• Objects of C++ can be static, stack dynamic or heap dynamic
• Explicit deallocation using the delete operator is required for heap-
dynamic objects because C++ does not include implicit storage
reclamation
63
Support for Object-Oriented
Programming in C++
• Many class definitions include a destructor method, which is implicitly
called when an object of the class ceases to exist
• Destructor is used to deallocate heap-allocated memory that is referenced
by data members
- It may also be used to record part or all of the state of the object
just before it dies, usually for debugging purposes
Inheritance
• A C++ class can be derived from an existing class, which is then its parent,
or base, class
• C++ class can also be stand-alone, without a superclass
• Data defined in a class definition -> Data Members of that class
• Functions defined in a class definition -> Member Functions of that class
(Methods)
• Some or all of the members of the base class may be inherited by the
derived class, which can also add new members and modify inherited
member functions
64
Support for Object-Oriented
Programming in C++
• All C++ objects must be initialized before they are used
• Therefore, all C++ classes include at least one constructor method that
initializes the data members of the new object
• Constructor methods are implicitly called when an object is created
• If any of the data members are pointers to heap-allocated data, the
constructor allocates that storage. Eg: int *a[] = new array[20];
• If a class has a parent, the inherited data members must be initialized
when the subclass object is created
- To do this, the parent constructor is implicitly called
• When initialization data must be furnished to the parent constructor, it is
given in the call to the subclass object constructor
65
Miscellaneous
class Base int main()
{
int x; {
public: Derived d(10, 5) ;
Base(int i)
{
}
x = i;
cout << "Base Parameterized Constructor\n";
cout << i;
}
};
Receives 2
class Derived : public Base
{ parameters as
argument and O/P: Base Parameterized Constructor
int y; 5
public: passes one
parameter to Derived Parameterized Constructor
Derived(int j, int p):Base(p)
base class 10
{
y = j; constructor
cout << “\nDerived Parameterized Constructor\n";
cout << y;
}
};
66
Miscellaneous
class Base int main()
{
int x; {
public: Derived d(10) ;
Base(int i)
{
}
x = i;
cout << "Base Parameterized Constructor\n";
cout << i;
}
};
Receives 1
class Derived : public Base
{ parameter as
O/P: Base Parameterized Constructor
int y; argument and
10
public: passes that
Derived Parameterized Constructor
Derived(int j):Base(j) parameter to
10
{ base class
y = j; constructor
cout << “\nDerived Parameterized Constructor\n";
cout << y;
}
};
67
Support for Object-Oriented
Programming
• If no constructor is included in a class definition, the compiler includes a
trivial constructor
• This default constructor calls the constructor of the parent class, if there is
a parent class
};
70
Miscellaneous
Inheritance -> Is
#include <iostream> int main() Unidirectional
using namespace std; {
//Base class Types
Parent obj; • Single Inheritance
class Parent
{ obj.id_p = 9; • Multiple Inheritance
public: Child obj1;
int id_p; obj1.id_c = 7;
}; obj1.id_p = 91;
cout << "Child id is " << obj1.id_c <<
class Child : private Parent
endl;
{
public: cout << "Parent id is " << obj1.id_p <<
int id_c; endl;
int Parent :: id_p;
}; return 0;
}
class child_derived: public Child
{ O/P: Child id is 7
Parent id is 91
};
71
Support for Object-Oriented
Programming
An example for the purpose and
use of private derivation
Nesting
Class
Nested
Class
• Note that nested classes have no special access to members of the nesting class. Only static data
members of the nesting class are visible to methods of the nested class
• Enclosing class, single_linked_list, has just a single data member, a pointer to act as the list’s header.
72
It contains a constructor function, which simply sets head to the null pointer value.
Support for Object-Oriented
Programming
• A client of a stack object could call insert_at_tail, thereby destroying the
integrity of its stack
• Likewise, a client of a queue object could call insert_at_head
• These unwanted accesses are allowed because both stack and queue are
subtypes of single_linked_list
• Our two example derived classes can be written to make them not
subtypes of their parent class by using private, rather than public,
derivation
• Then, both will also need to reexport empty, because it will become
hidden to their instances
• This situation illustrates the motivation for the private-derivation option
73
Support for Object-Oriented
Programming
74
Support for Object-Oriented
Programming
• The two versions of stack and queue illustrate the difference between
subtypes and derived types that are not subtypes
• The linked list is a generalization of both stacks and queues, because both
can be implemented as linked lists
• So, it is natural to inherit from a linked-list class to define stack and queue
classes
• However, neither is a subtype of the linked-list class, because both make
the public members of the parent class private, which makes them
inaccessible to clients
• One of the reasons friends are necessary is that sometimes a subprogram
must be written that can access the members of two different classes
• Eg: Suppose a program uses a class for vectors and one for matrices, and a
subprogram is needed to multiply a vector object times a matrix object
• In C++, the multiply function can be made a friend of both classes
75
Support for Object-Oriented
Programming
• C++ provides multiple inheritance, which allows more than one class to be
named as the parent of a new class
• Class DrawThread inherits all of the members of both Thread and Drawing
• If both Thread and Drawing happen to include members with the same name,
they can be unambiguously referenced in objects of class DrawThread by using
the scope resolution operator (::)
• Overriding methods in C++ must have exactly the same parameter profile as
the overridden method
• If there is any difference in the parameter profiles, the method in the subclass
is considered a new method that is unrelated to the method with the same
name in the ancestor class
• The return type of the overriding method either must be the same as that of
the overridden method or must be a publicly derived type of the return type
of the overridden method
76
Miscellaneous
class A class B
{
{
int idB;
int idA; void setId(int i)
void setId(int i) {
{ idB = i; Problem in
} Multiple
idA = i;
int getId() Inheritance
} {
int getId() return idB;
{ }
};
return idA; class AB : public A, public B
} {
}; };
int main()
{
AB *ab = new AB();
ab -> setID(5);
O/P: Error: request for member ‘setId’ is ambiguous }
Note: candidates are: void B::setId(int)
77
Note: void A::setId(int)
Miscellaneous
class B
class A {
A B
{ public:
public: int idB;
void setId(int i) AB
int idA; {
void setId(int i) idB = i;
}
{ int getId()
idA = i; {
return idB;
}
}
int getId() };
{ class AB : public A, public B
{
return idA; public:
} using A::setId;
using A::getId;
}; };
int main()
Note: Either use the one defined {
in “main” function (::) or use the AB *ab = new AB();
one defined in class AB (using) ab->B::setId(10);
} 78
Miscellaneous
class base int main() base
{ {
public:
virtual void print () base *bptr;
{
derived
derived d;
cout<< "print base class" <<endl;
} bptr = &d;
void show () //virtual function, binded at runtime (Runtime
{
cout<< "show base class" <<endl; polymorphism)
} bptr->print();
};
class derived: public base // Non-virtual function, binded at compile time
{ bptr->show();
public: This type of polymorphism is achieved
void print () //print () is already virtual
function in derived class, we could also by Function Overriding. Function
return 0;
declared as virtual void print () explicitly overriding occurs when a derived class
{ } has a definition for one of the member
cout<< "print derived class" <<endl; functions of the base class. That base
}
function is said to be overridden
void show ()
{ Types
cout<< "show derived class" <<endl; • Functional Overloading (Compile Time)
}
}; O/P: print derived class • Operator Overloading (Compile Time)
show base class • Virtual Functions (Run Time) 79
Dynamic Binding
• All of the member functions we have defined thus far are statically bound;
that is, a call to one of them is statically bound to a function definition
• A C++ object could be manipulated through a value variable, rather than a
pointer or a reference (Such an object would be static or stack dynamic)
• However, in that case, the object’s type is known and static, so dynamic
binding is not needed
• On the other hand, a pointer variable that has the type of a base class can
be used to point to any heap-dynamic objects of any class publicly derived
from that base class, making it a polymorphic variable
• Publicly derived subclasses are subtypes if none of the members of the
base class are private
• Privately derived subclasses are never subtypes
• A pointer to a base class cannot be used to reference a method in a
subclass that is not a subtype
80
Miscellaneous
class Vehicle class FourWheeler: public Vehicle
{
{
public:
public: FourWheeler()
Vehicle() {
{ cout << "This is a 4 wheeler
Vehicle" << endl;
cout << "This is a Vehicle" << endl; }
} void draw()
virtual void draw() {
cout<<"Fourwheeler Draw";
{
}
cout<<"Vehicle Draw"; };
} void main()
}; {
Vehicle *obj = new FourWheeler();
obj->draw();
FourWheeler *obj = new Vehicle(); } O/P: This is a Vehicle
O/P: error: invalid conversion from
‘Vehicle*’ to ‘FourWheeler*’ [-fpermissive]
This is a 4 wheeler Vehicle
81
Fourwheeler Draw
Dynamic Binding
• C++ does not allow value variables (as opposed to pointers or references)
to be polymorphic
• When a polymorphic variable is used to call a member function
overridden in one of the derived classes, the call must be dynamically
bound to the correct member function definition
• Member functions that must be dynamically bound must be declared to
be virtual functions by preceding their headers with the reserved word
virtual, which can appear only in a class body • Rect -> Value Variable
• Ptr_shape ->
Polymorphic Variable
83
Dynamic Binding
• Notice that the draw function in the definition of the base class shape is
set to 0
• This peculiar syntax is used to indicate that this member function is a pure
virtual function, meaning that it has no body and it cannot be called
• It must be redefined in derived classes if they call the function
• The purpose of a pure virtual function is to provide the interface of a
function without giving any of its implementation
• Pure virtual functions are usually defined when an actual member
function in the base class would not be useful
• Any class that includes a pure virtual function is an abstract class
• An abstract class can include completely defined methods
• It is illegal to instantiate an abstract class
• If a subclass of an abstract class does not redefine a pure virtual function
of its parent class, that function remains as a pure virtual function in the
subclass and the subclass is also an abstract class
• Abstract classes and inheritance together support a powerful technique
for software development
84
Dynamic Binding
• Dynamic binding allows the code that uses members like draw to be written
before all or even any of the versions of draw are written
• New derived classes could be added years later, without requiring any change
to the code that uses such dynamically bound members
• This is a highly useful feature of object-oriented languages
• Reference assignments for stack-dynamic objects are different from pointer
assignments for heap-dynamic objects
• In the assignment rect = sq, the member data from the object referenced by
sq would be assigned to the data members of the object referenced by rect,
but rect would still reference the Rectangle object
• Therefore, the call to draw through the object referenced by rect would be
that of the Rectangle class
• If rect and sq were pointers to heap-dynamic objects, the same assignment
would be a pointer assignment, which would make rect point to the Square
object, and a call to draw through rect would be bound dynamically to the 85
draw in the Square object
Miscellaneous
class Rectangle
{
int Length;
rect Length = 10
void draw() { .... } Length = -15
}; sq width = 5
class Square : public Rectangle
{
int width;
void draw() { .... } Copied
};
rect Length = -15
int main() Length = -15
{ sq
Square sq; width = 5
sq.Length = -15;
cout << sq.Length << endl;
sq.width = 5; O/P: -15
cout << sq.width << endl; 5
Rectangle rect; 10
rect.Length = 10;
-15
cout << rect.Length << endl;
rect = sq;
cout << rect.Length << endl;
rect.draw() It will call the method “draw” in class “Rectangle”
}
Note: In the assignment rect = sq, the member data from the object referenced by sq would be assigned86to
the data members of the object referenced by rect, but rect would still reference the Rectangle object
Miscellaneous
class Rectangle
{ rect Length = 10
int Length; Length = -15
void draw() { .... } sq width = 5
};
class Square : public Rectangle
{
int width; rect Length = 10
void draw() { .... }
Length = -15
}; sq
int main() width = 5
{
Square *sq; Note: If rect and sq were pointers to heap-
sq.Length = -15; dynamic objects, the same assignment would
sq.width = 5; be a pointer assignment, which would make
rect point to the Square object, and a call to
Rectangle *rect; draw through rect would be bound dynamically
rect.Length = 10; to the draw in the Square object
rect = sq;
rect.draw()
It will call the method “draw” in class “Square”
}
87
Implementation of Object-Oriented
Constructs
• Two parts of language support for object-oriented programming that pose
interesting questions for language implementers -> Storage structures for
instance variables; Dynamic bindings of messages to methods
Instance Data Storage
• In C++, classes are defined as extensions of C’s record structures—structs
• Similarity suggests a storage structure for the instance variables of class
instances—that of a record -> Class Instance Record (CIR)
• Structure of a CIR is static, so it is built at compile time and used as a
template for the creation of the data of class instances
• Every class has its own CIR
• When a derivation takes place, the CIR for the subclass is a copy of that of
the parent class, with entries for the new instance variables added at the
end
• Because the structure of the CIR is static, access to all instance variables
can be done as it is in records, using constant offsets from the beginning
of the CIR instance
• This makes these accesses as efficient as those for the fields of records
88
Implementation of Object-Oriented
Constructs
Java:
89
Dynamic Binding of Method Calls to
Methods
• Methods in a class that are statically bound need not be involved in the
CIR for the class
• However, methods that will be dynamically bound must have entries in
this structure
• Such entries could simply have a pointer to the code of the method, which
must be set at object creation time
• Calls to a method could then be connected to the corresponding code
through this pointer in the CIR
• Drawback to this technique is that every instance would need to store
pointers to all dynamically bound methods that could be called from the
instance
90
Dynamic Binding of Method Calls to
Methods
• Notice that the list of dynamically bound methods that can be called from
an instance of a class is the same for all instances of that class
• Therefore, the list of such methods must be stored only once
• So the CIR for an instance needs only a single pointer to that list to enable
it to find called methods
• The storage structure for the list is often called a virtual method table
(vtable)
• Method calls can be represented as offsets from the beginning of the
vtable
• Polymorphic variables of an ancestor class always reference the CIR of the
correct type object, so getting to the correct version of a dynamically
bound method is assured
• Multiple inheritance complicates the implementation of dynamic binding
91
Dynamic Binding of Method Calls to
Methods
92
Dynamic Binding of Method Calls to
Methods
• C class inherits the variable a and the init method from the A class
• It redefines the fun method, although both its fun and that of the parent class A
are potentially visible through a polymorphic variable (of type A)
• From B, C inherits the variable b and the sum method
• C defines its own variable, c, and defines an uninherited method, dud
• A CIR for C must include A’s data, B’s data, and C’s data, as well as some means of
accessing all visible methods
• Under single inheritance, the CIR would include a pointer to a vtable that has the
addresses of the code of all visible methods
• With multiple inheritance, however, it is not that simple
• There must be at least two different views available in the CIR—one for each of the
parent classes, one of which includes the view for the subclass, C
• This inclusion of the view of the subclass in the parent class’s view is just as in the
implementation of single inheritance
• There must also be two vtables: one for the A and C view and one for the B view
• The first part of the CIR for C in this case can be the C and A view, which begins
with a vtable pointer for the methods of C and those inherited from A, and includes
the data inherited from A
• Following this in C’s CIR is the B view part, which begins with a vtable pointer for
the virtual methods of B, which is followed by the data inherited from B and the
data defined in C 93