Module 4 - Oops
Module 4 - Oops
P=&emp;
P calculateSalary();
P=&emp1;
p->calculateSalary(); // Calls Manager's calculateSalary()
• P=&emp2;
• p->calculateSalary(); // Calls Engineer's calculateSalary()
•}
int main()
{
Employee emp;
manager emp1;
Engineer emp2;
ref_func(emp);
ref_func(emp1);
ref_func(emp2);
}
The virtual attribute is inherited
• When a virtual function is inherited, its virtual nature is also 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 is still be overridden.
• Put differently, no matter how many times a virtual function is
inherited , it remains virtual.
Class base
{
Public:
Virtual void vfunc()
{
Cout<<“this is base’s vfunc()”;
}
};
Class derived1 : public base
{
Public:
void vfunc()
{
Cout<<“this is derived1’s vfunc()”;
}
};
Class derived2 : public derived1
{
Public:
void vfunc() //vfunc is still virtual
{
Cout<<“this is derived2’s vfunc()”;
}
};
Void main()
{
Base *p,b;
Derived d1;
Derived d2;
P=&b;
Pvfunc();
p=&d1;
pvfunc();
p=&d2;
pvfunc();
Output:
This is base’s vfunc()
This is derived1’s vfunc()
This is derived2’s vfunc()
In this case, derived2 inherits derived1 rather than base, but vfunc() is still virtual
Virtual functions are
hierarchical
• When a function is declared as virtual by a base class, it may be
overridden by a derived class.
• However the function does not have to be overridden.
• When a derived class fails to override a virtual function, then when an
object of that derived class accesses that function, the function
defined by the base class is used.
Class base
{
Public:
Virtual void vfunc()
{
Cout<<“this is base’s vfunc()”;
}
};
Class derived1 : public base
{
Public:
void vfunc()
{
Cout<<“this is derived1’s vfunc()”;
}
};
Class derived2 : public base
{
Public:
//vfunc is not overridden by derived2, base’s vfunc is used here
};
Void main()
{
Base *p,b;
Derived d1;
Derived d2;
P=&b;
Pvfunc(); //access base’s vfunc
p=&d1;
pvfunc(); //access derived1’s vfunc
p=&d2;
pvfunc(); // uses base’s vfunc
}
• Because derived2 does not override vfunc(), the function defined by
base is used when vfunc() is referenced relative to objects of type
derived2.
P=&b;
Pvfunc(); // access base’s vfunc()
p=&d1;
pvfunc(); //access derived1’s vfunc()
p=&d2;
pvfunc(); // uses derived1’s vfunc()
}
Example for pure virtual function
Class base
{
Public:
Virtual void vfunc()=0;
};
Void main()
{
Base *p,b;
Derived d1;
Derived d2;
P=&b;
Pvfunc();
p=&d1;
pvfunc();
p=&d2;
pvfunc();
}
Write example of pure virtual function here…
Using Virtual Function
• One of the central aspect of using virtual function to get - “one
interface, multiple methods”.
• This is known as polymorphism. (occurring in different forms)
• In base class you create and define everything you can that relates to
the general case. The derived classes fills in the specific details.
• One simple example is as follows
• The base class name is convert which has two variables i.e val1 and val2.
val1 which hold the initial value and val2 holds the converted value.
• The convert class has compute as virtual function which can be used in
derived classes to compute the converted value.
Class convert
{
Public:
Double val1;
Double val2;
Virtual void compute()=0;
}
Class l_to_g : public convert // litre to gallons : 1 gallon = 3.78541 litres
{
Void compute()
{
Val2=val1/3.78541;
Cout<<val1<<“liters is =“<<val2<<“gallons”;
}
};
Class f_to_c : public Celsius
{
Public:
Void compute()
{
Val2=(val1-32)/1.8;
Cout<<val1<<“fahrenheit is =“<<val2<<“celsius”;
}
};
Void main()
{
Convert *p;
double val1;
L_to_g lgob;
lgob.val1 = val1;
p = &lgob;
p->compute();
cout << "Enter value in fahrenheit for conversion to celsius: ";
cin >> val1;
F_to_c fcob;
fcob.val1 = val1;
p = &fcob;
p->compute();
}
• One of the benefits of derived classes and virtual function is that
handling a new case is a very easy matter.
• For example, assuming the preceding program, you can add a
conversion from feet to meters by including this class:
• Class f_to_m : public convert
•{
• Public:
• Void compute()
•{
• Val2=val1/3.28;
•}
• };
Early binding vs Late binding
• Early binding refers to events that occur at compile time.
• In essence, early binding occurs when all information needed to call a function is known at compile time. (Put differently,
early binding means that an object and a function call are bound during compilation.)
• Examples of early binding include normal function calls (including standard library functions), overloaded function calls, and
overloaded operators.
• The main advantage to early binding is efficiency. Because all information necessary to call a function is determined at
compile time, these types of function calls are very fast. The opposite of early binding is late binding.
• As it relates to C++, late binding refers to function calls that are not resolved until run time. Virtual functions are used to
achieve late binding.
• As you know, when access is via a base pointer or reference, the virtual function actually called is determined by the type of
object pointed to by pointer.
• Because in most cases this cannot be determined at the compile time , the object and the function are not linked until run
time.
• The main advantage to late binding is flexibility. Unlike early binding, late binding allows you to create programs that can
respond to events occurring while the program executes without having to create a large amount of "contingency code.“
• Keep in mind that because a function call is not resolved until run time, late binding can make for somewhat slower
execution times.