Inheritance Ambiguity in C++
• In multiple inheritances, when one class is derived
from two or more base classes then there may be a
possibility that the base classes have functions with
the same name, and the derived class may not have
functions with that name as those of its base classes.
• If the derived class object needs to access one of the
similarly named member functions of the base
classes then it results in ambiguity because the
compiler gets confused about which base’s class
member function should be called.
class A {
public:
void func() { // Driver Code
cout << " I am in class A" << endl;
int main() {
}
}; // Created an object of class C
class B {
public: C obj;
void func() {
cout << " I am in class B" << endl; obj.func();
}
return 0;
}; }
class C: public A, public B {
};
output
prog.cpp: In function ‘int main()’:
prog.cpp:43:9: error: request for member ‘func’ is ambiguous
obj.func();
^
prog.cpp:21:10: note: candidates are: void B::func()
void func() {
^
prog.cpp:11:10: note: void A::func()
void func() {
^
Solution to Ambiguity:
• To solve this ambiguity scope resolution
operator is used denoted by ‘ :: ‘
• Syntax:
ObjectName.ClassName::FunctionName();
// Driver Code
int main() {
// Created an object of class C
C obj;
// Calling function func() in class A
obj.A::func();
// Calling function func() in class B
obj.B::func();
return 0;
}
Dynamic Polymorphism
What is Polymorphism?
• Polymorphism is the notion that can hold up the ability of
an object of a class to show different responses.
• To understand polymorphism, you can consider a real-life
example. You can relate it to the relationship of a person
with different people.
• A man can be a father to someone, a husband, a boss, an
employee, a son, a brother, or can have many other
relationships with various people.
• Here, this man represents the object, and his relationships
display the ability of this object to be represented in many
forms with totally different characteristics.
Types of Polymorphism
• Based on the functionality, you can categorize
polymorphism into two types:
I. Compile-time Polymorphism
II. Run-time Polymorphism.
Compile-Time Polymorphism
When the relationship between the definition of
different functions and their function calls, is
determined during the compile-time, it is known
as compile-time polymorphism.
This type of polymorphism is also known as
static or early binding polymorphism.
Compile-Time Polymorphism
The implementation of compile-time
polymorphism is achieved in two ways:
• Function overloading
• Operator overloading
Runtime Polymorphism
• Runtime polymorphism is also known as dynamic
polymorphism or late binding. In runtime
polymorphism, the function call is resolved at run
time.
• In contrast, to compile time or static
polymorphism, the compiler deduces the object at
run time and then decides which function call to
bind to the object.
• In C++, runtime polymorphism is implemented
using method overriding.
Runtime Polymorphism
• In a Runtime polymorphism, functions are called at the
time the program execution. Hence, it is known as late
binding or dynamic binding.
• Function overriding is a part of runtime polymorphism.
In function overriding, more than one method has the
same name with different types of the parameter list.
• It is achieved by using virtual functions and pointers. It
provides slow execution as it is known at the run time.
Thus, It is more flexible as all the things executed at
the run time.
Compile time polymorphism Run time polymorphism
The function to be invoked is known at The function to be invoked is known at
the compile time. the run time.
It is also known as overloading, early It is also known as overriding, Dynamic
binding and static binding. binding and late binding.
Overloading is a compile time Overriding is a run time polymorphism
polymorphism where more than one where more than one method is having
method is having the same name but the same name, number of parameters
with the different number of and the type of the parameters.
parameters or the type of the
parameters.
It is achieved by function overloading and It is achieved by virtual functions and
operator overloading. pointers.
It provides fast execution as it is known It provides slow execution as it is known
at the compile time. at the run time.
It is less flexible as mainly all the things It is more flexible as all the things
execute at the compile time. execute at the run time.
Function Overriding
• Function overriding is the mechanism using which a function
defined in the base class is once again defined in the derived
class. In this case, we say the function is overridden in the
derived class.
• We should remember that function overriding cannot be done
within a class. The function is overridden in the derived class
only. Hence inheritance should be present for function
overriding.
• The second thing is that the function from a base class that we
are overriding should have the same signature or prototype i.e.
it should have the same name, same return type and same
argument list.
#include <iostream>
using namespace std;
int main()
class Base
{
{ Base b;
public: Derived d;
void show_val() b.show_val();
d.show_val();
{ }
cout << "Class::Base"<<endl;
} Output:
}; Class::Base
class Derived:public Base Class::Derived
{
public:
void show_val() //function overridden from base
{
cout << "Class::Derived"<<endl;
}
};
Base Class Pointer Pointing to Derived Class Object in C++
• A pointer is a data type that stores the
address of other data types.
• Pointers can be used for base objects as well
as objects of derived classes.
• A pointer to the object of the derived class
and a pointer to the object of the base class
are type-compatible
The pointer of Base Class pointing different objects of the derived class
Base Class Pointer and Derived Class Object in C++:
• A base class pointer can point to a derived class object in
C++, but we can only access base class members using the
base class pointer.
• Now let us understand the base class pointer and drive
class object in C++ with examples.
• For a better understanding, please have a look at the
below code.
• So here we have created a class called Base. I
• n this class, we have three functions fun1(), fun2() and
fun3(). For a better understanding, please have a look at
the below image.
#include <iostream>
using namespace std;
class Base
{ int main()
public: {
void show_val() Base* b; //Base class pointer
{
b->show_val();
cout << "Class::Base";
} Derived d;
}; b = &d;
class Derived:public Base b->show_val();}
{
public:
void show_val() //overridden function Output:
{
Class::Base
cout << "Class::Derived"; } Class::Base
};
class Base { int main() {
public: Derived derived1;
void print() { Base* base1 = &derived1;
// code // calls function of Base class
} base1->print();
};
return 0;
}
class Derived : public Base {
public:
void print() {
// code
}
};
To avoid this, we declare the print() function of the
Base class as virtual by using the virtual keyword.
class Base {
public:
virtual void print() {
// code
}
};
#include <iostream>
using namespace std;
int main() {
Derived derived1;
class Base {
public: // pointer of Base type that points to
virtual void print() { derived1
cout << "Base Function" << endl; Base* base1 = &derived1;
}
// calls member function of Derived class
}; base1->print();
class Derived : public Base { return 0;
public: }
void print() {
cout << "Derived Function" << endl;
}
};
Virtual Function
• For the overridden function should be bound
dynamically to the function body, we make
the base class function virtual using the
“virtual” keyword. This virtual function is a
function that is overridden in the derived class
and the compiler carries out late or dynamic
binding for this function.
#include <iostream>
using namespace std;.
int main()
class Base {
{ Base* b; //Base class pointer
public: Derived d; //Derived class object
b = &d;
virtual void show_val() b->show_val(); //late Binding
{
cout << "Class::Base"; }
}
};
class Derived:public Base
{
Output:
public:
void show_val() Class::Derived
{
cout << "Class::Derived"; }
};
class Shape {
public:
// parameterized constructor
Shape(int l, int w)
{
length = l;
width = w;
}
int get_Area()
{
cout << "This is call to parent class area\n";
// Returning 1 in user-defined function means true
return 1;
}
protected:
int length, width;
};
// Derived class
class Square : public Shape {
public:
Square(int l = 0, int w = 0) : Shape(l, w)
{
} // declaring and initializing derived class
// constructor
int get_Area()
{
cout << "Square area: " << length * width << '\n';
return (length * width);
}
};
// Derived class
class Rectangle : public Shape {
public:
Rectangle(int l = 0, int w = 0)
: Shape(l, w)
{
} // declaring and initializing derived class
// constructor
int get_Area()
{
cout << "Rectangle area: " << length * width
<< '\n';
return (length * width);
}
};
int main()
{
Shape* s;
// Making object of child class Square
Square sq(5, 5);
// Making object of child class Rectangle
Rectangle rec(4, 5);
s = &sq; // reference variable
s->get_Area();
s = &rec; // reference variable
s->get_Area();
return 0; }
Output
• This is call to parent class area
• This is call to parent class area
• In the above example:
• We store the address of each child’s
class Rectangle and Square object in s and
• Then we call the get_Area() function on it, Ideally, it
should have called the respective get_Area() functions of
the child classes but Instead, it calls
the get_Area() defined in the base class.
• This happens due to static linkage which means the call
to get_Area() is getting set only once by the compiler
which is in the base class.
• C++ Program to Calculate the Area of Shapes
using Virtual Function
class Shape {
public:
// Usage of virtual constructor
virtual void calculate()
{
cout << "Area of your Shape ";
}
// usage of virtual Destuctor to avoid memory leak
};
class Rectangle : public Shape {
public:
int width, height, area;
void calculate()
{
cout << "Enter Width of Rectangle: ";
cin >> width;
cout << "Enter Height of Rectangle: ";
cin >> height;
area = height * width;
cout << "Area of Rectangle: " << area << "\n";
}
};
class Square : public Shape {
public:
int side, area;
void calculate()
{
cout << "Enter one side your of Square: ";
cin >> side;
area = side * side;
cout << "Area of Square: " << area << "\n";
}
};
int main()
{
// base class pointer
Shape* S;
Rectangle r;
// initialization of reference variable
S = &r;
// calling of Rectangle function
S->calculate();
Square sq
// initialization of reference variable
S = &sq;
// calling of Square function
S->calculate();
// return 0 to tell the program executed
// successfully
return 0;
}
Output:
Enter Width of Rectangle: 10
Height of Rectangle: 20
Area of Rectangle: 200
Enter one side your of Square: 16
Area of Square: 256
#include <iostream>
using namespace std;
class A
{ public:
virtual void show() int main()
{ cout<<"A"; {
}};
class B :public A{
A* p= new C();
public: p->show();
void show() return 0;}
{ cout<<"B";
}};
class C :public B
{ public:
void show()
{ cout<<"C";
} };
What is the use?
•
Virtual functions allow us to create a list of
base class pointers and call methods of any of
the derived classes without even knowing the
kind of derived class object.
Rules for Virtual Functions
The rules for the virtual functions in C++ are as follows:
• Virtual functions cannot be static.
• A virtual function can be a friend function of another class.
• Virtual functions should be accessed using a pointer or
reference of base class type to achieve runtime
polymorphism.
• The prototype of virtual functions should be the same in the
base as well as the derived class.
• They are always defined in the base class and overridden in a
derived class. It is not mandatory for the derived class to
override (or re-define the virtual function), in that case, the
base class version of the function is used.
• A class may have a virtual destructor but it cannot have a
virtual constructor.
Real-Life Example to Understand the Implementation of Virtual
Function
• Consider employee management software for
an organization.
Let the code has a simple base class Employee,
the class contains virtual functions
like raiseSalary(), transfer(), promote(), etc.
Different types of employees
like Managers, Engineers, etc., may have their
own implementations of the virtual functions
present in base class Employee.
• In our complete software, we just need to pass a
list of employees everywhere and call appropriate
functions without even knowing the type of
employee. For example, we can easily raise the
salary of all employees by iterating through the list
of employees. Every type of employee may have its
own logic in its class, but we don’t need to worry
about them because if raiseSalary() is present for a
specific employee type, only that function would
be called.
• In C++, the overridden function in derived
class can also be private. The compiler only
checks the type of the object at compile time
and binds the function at run time, hence it
doesn’t make any difference even if the
function is public or private.
• Note that if a function is declared virtual in the
base class, then it will be virtual in all of the
derived classes.
What Are the Rules of Virtual Function in C++?
• There are a few rules you need to follow to create a virtual function
in C++. These rules are:
The functions cannot be static
You derive them using the “virtual” keyword
Virtual functions in C++ needs to be a member of some other class
(base class)
They can be a friend function of another class
The prototype of these functions should be the same for both the
base and derived class
Virtual functions are accessible using object pointers
Redefining the virtual function in the derived class is optional, but it
needs to be defined in the base class
The function call resolving is done at run-time
You can create a virtual destructor but not a constructor
Pointers and Inheritance
Can we call fun4 and fun5?
No, we cannot call these functions.
• The point that we learn here is that you can have a base
class pointer and a derived class object attached to it and
you can call only those functions which are present in the
base class.
• You cannot call the functions which are defined in the
derived class. But the object is a derived class object.
• So, you can call only those functions which are present in
the base class because the pointer reference or pointer is
the base class.
#include <iostream>
using namespace std;
class BaseClass {
public:
int var_base;
virtual void display()
{
cout << "Displaying Base class"
<< " variable var_base: " << var_base << endl;
}
};
class DerivedClass : public BaseClass {
public:
int var_derived;
void display()
{
cout << "Displaying Base class"
<< "variable var_base: " << var_base << endl;
cout << "Displaying Derived "
<< " class variable var_derived: "
<< var_derived << endl;
}
};
// Driver Code
int main()
{
// Pointer to base class
BaseClass* b_p;
BaseClass obj_base;
DerivedClass obj_der;
b_p = &obj_der;
b_p->var_base = 34;
// b_p->var_derived = 98;
// output: error: ‘class BaseClass’ has no member named
// ‘var_derived’
b_p->display();
b_p->var_base = 3400;
b_p->display();
DerivedClass* d_p;
d_p = &obj_derived;
d_p->var_base = 9448;
d_p->var_derived = 98;
d_p->display();
return 0;
}
Output
• Displaying Base class variable var_base: 34
Displaying Base class variable var_base: 3400
Displaying Base classvariable var_base: 9448
Displaying Derived class variable var_derived:
98
• Now we see, that the output is “Class:: Base”. So
irrespective of what type object the base pointer is
holding, the program outputs the contents of the
function of the class whose base pointer is the type
of. In this case, also static linking is carried out.
• In order to make the base pointer output, correct
contents and proper linking, we go for dynamic
binding of functions. This is achieved using Virtual
functions mechanism which is explained in the next
section.
Example1: We cannot access derived class functions using the
base class pointer in C++.
class Base
{ int main()
public: {
void fun1() Base *p;
{ p = new Derived();
cout << "fun1 of Base Class" << endl; p->fun1();
} //The following statement will
}; give compilation error
class Derived:public Base p->fun2(); //error: ‘class Base’
{ has no member named ‘fun2’; did
public:void fun2() you mean ‘fun1’?
{ return 0;
cout << "fun2 of Derived Class" << endl; }
}
};
Output:
Example2: Rectangle and Cuboid Example
class Rectangle
{ int main()
public: {
void Area() Rectangle *r;
{ r = new Cuboid();
cout << "Area Function of Rectangle" << endl; r->Area();
} r->Perimeter();
void Perimeter() //The following function call will give
{ compilation error
cout << "Perimeter Function of Rectangle" << endl; r->Volume(); //error: ‘class Rectangle’ has
} member named ‘Volume’
}; return 0;
class Cuboid:public Rectangle }
{ Outp
public:
void Volume()
{
cout << "Volume Function pf Cuboid" << endl;
}
};
Output:
Example3: Derived Class Pointer and Base Class Object in C++
class Rectangle
{ int main()
public: {
Rectangle r;
void Area() Cuboid *c = &r;
{ c->Area();
cout << "Area Function of Rectangle" << endl; c->Perimeter();
c->Volume();
}
return 0;
void Perimeter() }
{
cout << "Perimeter Function of Rectangle" << endl;
}};
class Cuboid:public Rectangle
{
public:
void Volume()
{
cout << "Volume Function pf Cuboid" << endl;
}
Output:
Example4: Basic Car and Advanced Car Example
class BasicCar
{
public: int main()
void Start() {
{ AdvanceCar a;
cout << "Car Started" << endl; BasicCar *ptr = &a;
} ptr->Start();
};
//The following statement will throw
compilation error
class AdvanceCar:public BasicCar
ptr->PlayMusic(); //error: ‘class BasicCar’ has
{
no member named ‘PlayMusic’
public:
return 0;
void PlayMusic()
}
{
cout << "Playing Music" << endl;
}
};
Output:
class BasicCar
{ int main()
public: {
void Start() BasicCar b;
{ AdvanceCar *ptr = &b;
cout << "Car Started" << endl; ptr->Start();
} ptr->PlayMusic();
}; return 0;
class AdvanceCar:public BasicCar }
{
public:
void PlayMusic()
{
cout << "Playing Music" << endl;
}
Output:
Virtual Destructor
What is Virtual Destructor in C++?
• A destructor in C++ is a class member function that
is implicitly invoked when the scope of a class
object ends.
• Same as a constructor, which is also invoked
implicitly when an object of a class is created.
• A destructor is used to free up the resources
occupied by an object.
• The destructor function has the same name as that
of a class, but a tilde (~) sign is used before writing
the function's name.
Virtual Destructor
• Deleting a derived class object using a pointer
of base class type that has a non-virtual
destructor results in undefined behavior. To
correct this situation, the base class should be
defined with a virtual destructor.
For example, the following program results in
undefined behavior.
class base {
public:
int main()
base()
{
{ cout << "Constructing base\n"; } derived *d = new derived();
~base() base *b = d;
{ cout<< "Destructing base\n"; } delete b;
}; return 0;
}
class derived: public base {
public:
derived()
{ cout << "Constructing derived\n"; }
~derived()
{ cout << "Destructing derived\n"; }
};
Output
Constructing base
Constructing derived
Destructing base
• Making base class destructor virtual
guarantees that the object of derived class is
destructed properly, i.e., both base class and
derived class destructors are called. For
example,
class base { int main()
public: {
base() derived *d = new derived();
{ cout << "Constructing base\n"; } base *b = d;
virtual ~base() delete b;
getchar();
{ cout << "Destructing base\n"; }
return 0;
}; }
class derived : public base { Constructing base
Constructing derived
public: Destructing derived
derived() Destructing base
{ cout << "Constructing derived\n"; }
~derived()
{ cout << "Destructing derived\n"; }
};
// deriv_VirtualFunctions.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class Account {
public:
Account( double d ) { _balance = d; }
virtual ~Account() {}
virtual double GetBalance() { return _balance; }
virtual void PrintBalance() { cerr << "Error. Balance not available for base
type." << endl; }
private:
double _balance;
};
class CheckingAccount : public Account {
public:
CheckingAccount(double d) : Account(d) {}
void PrintBalance() { cout << "Checking account balance: " <<
GetBalance() << endl; }
};
class SavingsAccount : public Account {
public:
SavingsAccount(double d) : Account(d) {}
void PrintBalance() { cout << "Savings account balance: " <<
GetBalance(); }
};
int main() {
// Create objects of type CheckingAccount and SavingsAccount.
CheckingAccount checking( 100.00 );
SavingsAccount savings( 1000.00 );
// Call PrintBalance using a pointer to Account.
Account *pAccount = &checking;
pAccount->PrintBalance();
// Call PrintBalance using a pointer to Account.
pAccount = &savings;
pAccount->PrintBalance();
}