UNIT-4
Inheritance & Virtual Function
In C++, inheritance is a process in which one object acquires all the properties and behaviors of its parent object automatically. In such way, you can reuse, extend or modify the attributes and behaviours which are defined in other class.
In C++, the class which inherits the members of another class is called derived class and the class whose members are inherited is called base class. The derived class is the specialized class for the base class.
Code reusability: Now you can reuse the members of your parent class. So, there is no need to define the member again. So less code is required in the class.
C++ supports five types of inheritance:
- Single inheritance
- Multiple inheritance
- Hierarchical inheritance
- Multilevel inheritance
- Hybrid inheritance
Fig 1 - Inheritance
A Derived class is defined as the class derived from the base class.
The Syntax of Derived class:
- class derived_class_name :: visibility-mode base_class_name
- {
- // body of the derived class.
- }
Where,
derived_class_name: It is the name of the derived class.
visibility mode: The visibility mode specifies whether the features of the base class are publicly inherited or privately inherited. It can be public or private.
base_class_name: It is the name of the base class.
- When the base class is privately inherited by the derived class, public members of the base class becomes the private members of the derived class. Therefore, the public members of the base class are not accessible by the objects of the derived class only by the member functions of the derived class.
- When the base class is publicly inherited by the derived class, public members of the base class also become the public members of the derived class. Therefore, the public members of the base class are accessible by the objects of the derived class as well as by the member functions of the base class.
- In C++, the default mode of visibility is private.
- The private members of the base class are never inherited.
Single inheritance is defined as the inheritance in which a derived class is inherited from the only one base class.
Fig 2 - Single inheritance
Where 'A' is the base class, and 'B' is the derived class.
C++ Single Level Inheritance Example: Inheriting Fields
When one class inherits another class, it is known as single level inheritance. Let's see the example of single level inheritance which inherits the fields only.
- #include <iostream>
- using namespace std;
- class Account {
- public:
- float salary = 60000;
- };
- class Programmer: public Account {
- public:
- float bonus = 5000;
- };
- int main(void) {
- Programmer p1;
- cout<<"Salary: "<<p1.salary<<endl;
- cout<<"Bonus: "<<p1.bonus<<endl;
- return 0;
- }
Output:
Salary: 60000
Bonus: 5000
In the above example, Employee is the base class and Programmer is the derived class.
C++ Single Level Inheritance Example: Inheriting Methods
Let's see another example of inheritance in C++ which inherits methods only.
- #include <iostream>
- using namespace std;
- class Animal {
- public:
- void eat() {
- cout<<"Eating..."<<endl;
- }
- };
- class Dog: public Animal
- {
- public:
- void bark(){
- cout<<"Barking...";
- }
- };
- int main(void) {
- Dog d1;
- d1.eat();
- d1.bark();
- return 0;
- }
Output:
Eating...
Barking...
Let's see a simple example.
- #include <iostream>
- using namespace std;
- class A
- {
- int a = 4;
- int b = 5;
- public:
- int mul()
- {
- int c = a*b;
- return c;
- }
- };
- class B : private A
- {
- public:
- void display()
- {
- int result = mul();
- std::cout <<"Multiplication of a and b is : "<<result<< std::endl;
- }
- };
- int main()
- {
- B b;
- b.display();
- return 0;
- }
Output:
Multiplication of a and b is : 20
In the above example, class A is privately inherited. Therefore, the mul() function of class 'A' cannot be accessed by the object of class B. It can only be accessed by the member function of class B.
How to make a Private Member Inheritable
The private member is not inheritable. If we modify the visibility mode by making it public, but this takes away the advantage of data hiding.
C++ introduces a third visibility modifier, i.e., protected. The member which is declared as protected will be accessible to all the member functions within the class as well as the class immediately derived from it.
Visibility modes can be classified into three categories:
Fig 3 - Visibility modes
- Public: When the member is declared as public, it is accessible to all the functions of the program.
- Private: When the member is declared as private, it is accessible within the class only.
- Protected: When the member is declared as protected, it is accessible within its own class as well as the class immediately derived from it.
Visibility of Inherited Members
Base class visibility | Derived class visibility | ||
Public | Private | Protected | |
Private | Not Inherited | Not Inherited | Not Inherited |
Protected | Protected | Private | Protected |
Public | Public | Private | Protected |
Multilevel inheritance is a process of deriving a class from another derived class.
Fig 4 - Multilevel inheritance
C++ Multi Level Inheritance Example
When one class inherits another class which is further inherited by another class, it is known as multi level inheritance in C++. Inheritance is transitive so the last derived class acquires all the members of all its base classes.
Let's see the example of multi level inheritance in C++.
- #include <iostream>
- using namespace std;
- class Animal {
- public:
- void eat() {
- cout<<"Eating..."<<endl;
- }
- };
- class Dog: public Animal
- {
- public:
- void bark(){
- cout<<"Barking..."<<endl;
- }
- };
- class BabyDog: public Dog
- {
- public:
- void weep() {
- cout<<"Weeping...";
- }
- };
- int main(void) {
- BabyDog d1;
- d1.eat();
- d1.bark();
- d1.weep();
- return 0;
- }
Output:
Eating...
Barking...
Weeping...
Multiple inheritance is the process of deriving a new class that inherits the attributes from two or more classes.
Fig 5 – Derived class
Syntax of the Derived class:
- class D : visibility B-1, visibility B-2, ?
- {
- // Body of the class;
- }
Let's see a simple example of multiple inheritance.
- #include <iostream>
- using namespace std;
- class A
- {
- protected:
- int a;
- public:
- void get_a(int n)
- {
- a = n;
- }
- };
- class B
- {
- protected:
- int b;
- public:
- void get_b(int n)
- {
- b = n;
- }
- };
- class C : public A,public B
- {
- public:
- void display()
- {
- std::cout << "The value of a is : " <<a<< std::endl;
- std::cout << "The value of b is : " <<b<< std::endl;
- cout<<"Addition of a and b is : "<<a+b;
- }
- };
- int main()
- {
- C c;
- c.get_a(10);
- c.get_b(20);
- c.display();
- return 0;
- }
Output:
The value of a is : 10
The value of b is : 20
Addition of a and b is : 30
In the above example, class 'C' inherits two base classes 'A' and 'B' in a public mode.
Ambiquity Resolution in Inheritance
Ambiguity can be occurred in using the multiple inheritance when a function with the same name occurs in more than one base class.
Let's understand this through an example:
- #include <iostream>
- using namespace std;
- class A
- {
- public:
- void display()
- {
- std::cout << "Class A" << std::endl;
- }
- };
- class B
- {
- public:
- void display()
- {
- std::cout << "Class B" << std::endl;
- }
- };
- class C : public A, public B
- {
- void view()
- {
- display();
- }
- };
- int main()
- {
- C c;
- c.display();
- return 0;
- }
Output:
error: reference to 'display' is ambiguous
display();
- The above issue can be resolved by using the class resolution operator with the function. In the above example, the derived class code can be rewritten as:
- class C : public A, public B
- {
- void view()
- {
- A :: display(); // Calling the display() function of class A.
- B :: display(); // Calling the display() function of class B.
- }
- };
An ambiguity can also occur in single inheritance.
Consider the following situation:
- class A
- {
- public:
- void display()
- {
- cout<<?Class A?;
- }
- } ;
- class B
- {
- public:
- void display()
- {
- cout<<?Class B?;
- }
- } ;
In the above case, the function of the derived class overrides the method of the base class. Therefore, call to the display() function will simply call the function defined in the derived class. If we want to invoke the base class function, we can use the class resolution operator.
- int main()
- {
- B b;
- b.display(); // Calling the display() function of B class.
- b.B :: display(); // Calling the display() function defined in B class.
- }
Hybrid inheritance is a combination of more than one type of inheritance.
Fig 6 - Hybrid inheritance
Let's see a simple example:
- #include <iostream>
- using namespace std;
- class A
- {
- protected:
- int a;
- public:
- void get_a()
- {
- std::cout << "Enter the value of 'a' : " << std::endl;
- cin>>a;
- }
- };
- class B : public A
- {
- protected:
- int b;
- public:
- void get_b()
- {
- std::cout << "Enter the value of 'b' : " << std::endl;
- cin>>b;
- }
- };
- class C
- {
- protected:
- int c;
- public:
- void get_c()
- {
- std::cout << "Enter the value of c is : " << std::endl;
- cin>>c;
- }
- };
- class D : public B, public C
- {
- protected:
- int d;
- public:
- void mul()
- {
- get_a();
- get_b();
- get_c();
- std::cout << "Multiplication of a,b,c is : " <<a*b*c<< std::endl;
- }
- };
- int main()
- {
- D d;
- d.mul();
- return 0;
- }
Output:
Enter the value of 'a' :
10
Enter the value of 'b' :
20
Enter the value of c is :
30
Multiplication of a,b,c is : 6000
Hierarchical inheritance is defined as the process of deriving more than one class from a base class.
Fig 7 - Hierarchical inheritance
Syntax of Hierarchical inheritance:
- class A
- {
- // body of the class A.
- }
- class B : public A
- {
- // body of class B.
- }
- class C : public A
- {
- // body of class C.
- }
- class D : public A
- {
- // body of class D.
- }
Let's see a simple example:
- #include <iostream>
- using namespace std;
- class Shape // Declaration of base class.
- {
- public:
- int a;
- int b;
- void get_data(int n,int m)
- {
- a= n;
- b = m;
- }
- };
- class Rectangle : public Shape // inheriting Shape class
- {
- public:
- int rect_area()
- {
- int result = a*b;
- return result;
- }
- };
- class Triangle : public Shape // inheriting Shape class
- {
- public:
- int triangle_area()
- {
- float result = 0.5*a*b;
- return result;
- }
- };
- int main()
- {
- Rectangle r;
- Triangle t;
- int length,breadth,base,height;
- std::cout << "Enter the length and breadth of a rectangle: " << std::endl;
- cin>>length>>breadth;
- r.get_data(length,breadth);
- int m = r.rect_area();
- std::cout << "Area of the rectangle is : " <<m<< std::endl;
- std::cout << "Enter the base and height of the triangle: " << std::endl;
- cin>>base>>height;
- t.get_data(base,height);
- float n = t.triangle_area();
- std::cout <<"Area of the triangle is : " << n<<std::endl;
- return 0;
- }
Output:
Enter the length and breadth of a rectangle:
23
20
Area of the rectangle is : 460
Enter the base and height of the triangle:
2
5
Area of the triangle is : 5
Key takeaway
In C++, inheritance is a process in which one object acquires all the properties and behaviors of its parent object automatically. In such way, you can reuse, extend or modify the attributes and behaviours which are defined in other class.
In C++, the class which inherits the members of another class is called derived class and the class whose members are inherited is called base class. The derived class is the specialized class for the base class.
One of the most important concepts in object-oriented programming is that of inheritance. Inheritance allows us to define a class in terms of another class, which makes it easier to create and maintain an application. This also provides an opportunity to reuse the code functionality and fast implementation time.
When creating a class, instead of writing completely new data members and member functions, the programmer can designate that the new class should inherit the members of an existing class. This existing class is called the base class, and the new class is referred to as the derived class.
The idea of inheritance implements the is a relationship. For example, mammal IS-A animal, dog IS-A mammal hence dog IS-A animal as well and so on.
A class can be derived from more than one classes, which means it can inherit data and functions from multiple base classes. To define a derived class, we use a class derivation list to specify the base class(es). A class derivation list names one or more base classes and has the form −
class derived-class: access-specifier base-class
Where access-specifier is one of public, protected, or private, and base-class is the name of a previously defined class. If the access-specifier is not used, then it is private by default.
Consider a base class Shape and its derived class Rectangle as follows −
#include <iostream>
using namespace std;
// Base class
class Shape {
public:
void setWidth(int w) {
width = w;
}
void setHeight(int h) {
height = h;
}
protected:
int width;
int height;
};
// Derived class
class Rectangle: public Shape {
public:
int getArea() {
return (width * height);
}
};
int main(void) {
Rectangle Rect;
Rect.setWidth(5);
Rect.setHeight(7);
// Print the area of the object.
cout << "Total area: " << Rect.getArea() << endl;
return 0;
}
When the above code is compiled and executed, it produces the following result −
Total area: 35
Access Control and Inheritance
A derived class can access all the non-private members of its base class. Thus base-class members that should not be accessible to the member functions of derived classes should be declared private in the base class.
We can summarize the different access types according to - who can access them in the following way −
Access | Public | protected | private |
Same class | Yes | yes | yes |
Derived classes | Yes | yes | no |
Outside classes | Yes | no | no |
A derived class inherits all base class methods with the following exceptions −
- Constructors, destructors and copy constructors of the base class.
- Overloaded operators of the base class.
- The friend functions of the base class.
When deriving a class from a base class, the base class may be inherited through public, protected or private inheritance. The type of inheritance is specified by the access-specifier as explained above.
We hardly use protected or private inheritance, but public inheritance is commonly used. While using different type of inheritance, following rules are applied −
- Public Inheritance − When deriving a class from a public base class, public members of the base class become public members of the derived class and protected members of the base class become protected members of the derived class. A base class's private members are never accessible directly from a derived class, but can be accessed through calls to the public and protected members of the base class.
- Protected Inheritance − When deriving from a protected base class, public and protected members of the base class become protected members of the derived class.
- Private Inheritance − When deriving from a private base class, public and protected members of the base class become private members of the derived class.
A C++ class can inherit members from more than one class and here is the extended syntax −
class derived-class: access baseA, access baseB....
Where access is one of public, protected, or private and would be given for every base class and they will be separated by comma as shown above. Let us try the following example –
#include <iostream>
using namespace std;
// Base class Shape
class Shape {
public:
void setWidth(int w) {
width = w;
}
void setHeight(int h) {
height = h;
}
protected:
int width;
int height;
};
// Base class PaintCost
class PaintCost {
public:
int getCost(int area) {
return area * 70;
}
};
// Derived class
class Rectangle: public Shape, public PaintCost {
public:
int getArea() {
return (width * height);
}
};
int main(void) {
Rectangle Rect;
int area;
Rect.setWidth(5);
Rect.setHeight(7);
area = Rect.getArea();
// Print the area of the object.
cout << "Total area: " << Rect.getArea() << endl;
// Print the total cost of painting
cout << "Total paint cost: $" << Rect.getCost(area) << endl;
return 0;
}
When the above code is compiled and executed, it produces the following result −
Total area: 35
Total paint cost: $2450
Pass parameter base classes
#include <iostream>
using namespace std;
class base1 {
protected:
int i;
public:
base1(int x) {
i=x;
cout << "Constructing base1\n";
}
~base1() {
cout << "Destructing base1\n";
}
};
class base2 {
protected:
int k;
public:
base2(int x) {
k=x;
cout << "Constructing base2\n";
}
~base2() {
cout << "Destructing base2\n";
}
};
class derived: public base1, public base2 {
int j;
public:
derived(int x, int y, int z): base1(y), base2(z){
j=x;
cout << "Constructing derived\n";
}
~derived() {
cout << "Destructing derived\n";
}
void show() {
cout << i << " " << j << " " << k << "\n";
}
};
int main()
{
derived ob(3, 4, 5);
ob.show();
return 0;
}
Constructing base1
Constructing base2
Constructing derived
4 3 5
Destructing derived
Destructing base2
Destructing base1
Key takeaway
One of the most important concepts in object-oriented programming is that of inheritance. Inheritance allows us to define a class in terms of another class, which makes it easier to create and maintain an application. This also provides an opportunity to reuse the code functionality and fast implementation time.
When creating a class, instead of writing completely new data members and member functions, the programmer can designate that the new class should inherit the members of an existing class. This existing class is called the base class, and the new class is referred to as the derived class.
- A C++ virtual function is a member function in the base class that you redefine in a derived class. It is declared using the virtual keyword.
- It is used to tell the compiler to perform dynamic linkage or late binding on the function.
- There is a necessity to use the single pointer to refer to all the objects of the different classes. So, we create the pointer to the base class that refers to all the derived objects. But, when base class pointer contains the address of the derived class object, always executes the base class function. This issue can only be resolved by using the 'virtual' function.
- A 'virtual' is a keyword preceding the normal declaration of a function.
- When the function is made virtual, C++ determines which function is to be invoked at the runtime based on the type of the object pointed by the base class pointer.
Late binding or Dynamic linkage
In late binding function call is resolved during runtime. Therefore compiler determines the type of object at runtime, and then binds the function call.
Rules of Virtual Function
- Virtual functions must be members of some class.
- Virtual functions cannot be static members.
- They are accessed through object pointers.
- They can be a friend of another class.
- A virtual function must be defined in the base class, even though it is not used.
- The prototypes of a virtual function of the base class and all the derived classes must be identical. If the two functions with the same name but different prototypes, C++ will consider them as the overloaded functions.
- We cannot have a virtual constructor, but we can have a virtual destructor
- Consider the situation when we don't use the virtual keyword.
- #include <iostream>
- using namespace std;
- class A
- {
- int x=5;
- public:
- void display()
- {
- std::cout << "Value of x is : " << x<<std::endl;
- }
- };
- class B: public A
- {
- int y = 10;
- public:
- void display()
- {
- std::cout << "Value of y is : " <<y<< std::endl;
- }
- };
- int main()
- {
- A *a;
- B b;
- a = &b;
- a->display();
- return 0;
- }
Output:
Value of x is : 5
In the above example, * a is the base class pointer. The pointer can only access the base class members but not the members of the derived class. Although C++ permits the base pointer to point to any object derived from the base class, it cannot directly access the members of the derived class. Therefore, there is a need for virtual function which allows the base pointer to access the members of the derived class.
Let's see the simple example of C++ virtual function used to invoked the derived class in a program.
- #include <iostream>
- {
- public:
- virtual void display()
- {
- cout << "Base class is invoked"<<endl;
- }
- };
- class B:public A
- {
- public:
- void display()
- {
- cout << "Derived Class is invoked"<<endl;
- }
- };
- int main()
- {
- A* a; //pointer of base class
- B b; //object of derived class
- a = &b;
- a->display(); //Late Binding occurs
- }
Output:
Derived Class is invoked
- A virtual function is not used for performing any task. It only serves as a placeholder.
- When the function has no definition, such function is known as "do-nothing" function.
- The "do-nothing" function is known as a pure virtual function. A pure virtual function is a function declared in the base class that has no definition relative to the base class.
- A class containing the pure virtual function cannot be used to declare the objects of its own, such classes are known as abstract base classes.
- The main objective of the base class is to provide the traits to the derived classes and to create the base pointer used for achieving the runtime polymorphism.
Pure virtual function can be defined as:
- virtual void display() = 0;
Let's see a simple example:
- #include <iostream>
- using namespace std;
- class Base
- {
- public:
- virtual void show() = 0;
- };
- class Derived : public Base
- {
- public:
- void show()
- {
- std::cout << "Derived class is derived from the base class." << std::endl;
- }
- };
- int main()
- {
- Base *bptr;
- //Base b;
- Derived d;
- bptr = &d;
- bptr->show();
- return 0;
- }
Output:
Derived class is derived from the base class.
In the above example, the base class contains the pure virtual function. Therefore, the base class is an abstract base class. We cannot create the object of the base class.
Key takeaway
- A C++ virtual function is a member function in the base class that you redefine in a derived class. It is declared using the virtual keyword.
- It is used to tell the compiler to perform dynamic linkage or late binding on the function.
- There is a necessity to use the single pointer to refer to all the objects of the different classes. So, we create the pointer to the base class that refers to all the derived objects. But, when base class pointer contains the address of the derived class object, always executes the base class function. This issue can only be resolved by using the 'virtual' function.
- A 'virtual' is a keyword preceding the normal declaration of a function.
- When the function is made virtual, C++ determines which function is to be invoked at the runtime based on the type of the object pointed by the base class pointer.
A virtual function is a member function in the base class that we expect to redefine in derived classes.
Basically, a virtual function is used in the base class in order to ensure that the function is overridden. This especially applies to cases where a pointer of base class points to an object of a derived class.
For example, consider the code below:
class Base {
public:
void print() {
// code
}
};
class Derived : public Base {
public:
void print() {
// code
}
};
Later, if we create a pointer of Base type to point to an object of Derived class and call the print() function, it calls the print() function of the Base class.
In other words, the member function of Base is not overridden.
int main() {
Derived derived1;
Base* base1 = &derived1;
// calls function of Base class
base1->print();
return 0;
}
In order 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
}
};
Example 1: C++ virtual Function
#include <iostream>
using namespace std;
class Base {
public:
virtual void print() {
cout << "Base Function" << endl;
}
};
class Derived : public Base {
public:
void print() {
cout << "Derived Function" << endl;
}
};
int main() {
Derived derived1;
// pointer of Base type that points to derived1
Base* base1 = &derived1;
// calls member function of Derived class
base1->print();
return 0;
}
Output
Derived Function
Here, we have declared the print() function of Base as virtual.
So, this function is overridden even when we use a pointer of Base type that points to the Derived object derived1.
Working of virtual functions in C++
C++ 11 has given us a new identifier override that is very useful to avoid bugs while using virtual functions.
This identifier specifies the member functions of the derived classes that override the member function of the base class.
For example,
class Base {
public:
virtual void print() {
// code
}
};
class Derived : public Base {
public:
void print() override {
// code
}
};
If we use a function prototype in Derived class and define that function outside of the class, then we use the following code:
class Derived : public Base {
public:
// function prototype
void print() override;
};
// function definition
void Derived::print() {
// code
}
When using virtual functions. it is possible to make mistakes while declaring the member functions of the derived classes.
Using the override identifier prompts the compiler to display error messages when these mistakes are made.
Otherwise, the program will simply compile but the virtual function will not be overridden.
Some of these possible mistakes are:
- Functions with incorrect names: For example, if the virtual function in the base class is named print(), but we accidentally name the overriding function in the derived class as pint().
- Functions with different return types: If the virtual function is, say, of void type but the function in the derived class is of int type.
- Functions with different parameters: If the parameters of the virtual function and the functions in the derived classes don't match.
- No virtual function is declared in the base class.
Suppose we have a base class Animal and derived classes Dog and Cat.
Suppose each class has a data member named type. Suppose these variables are initialized through their respective constructors.
class Animal {
private:
string type;
... .. ...
public:
Animal(): type("Animal") {}
... .. ...
};
class Dog : public Animal {
private:
string type;
... .. ...
public:
Animal(): type("Dog") {}
... .. ...
};
class Cat : public Animal {
private:
string type;
... .. ...
public:
Animal(): type("Cat") {}
... .. ...
};
Now, let us suppose that our program requires us to create two public functions for each class:
- getType() to return the value of type
- print() to print the value of type
We could create both these functions in each class separately and override them, which will be long and tedious.
Or we could make getType() virtual in the Animal class, then create a single, separate print() function that accepts a pointer of Animal type as its argument. We can then use this single function to override the virtual function.
class Animal {
... .. ...
public:
... .. ...
virtual string getType {...}
};
... .. ...
... .. ...
void print(Animal* ani) {
cout << "Animal: " << ani->getType() << endl;
}
This will make the code shorter, cleaner, and less repetitive.
Example 2: C++ virtual Function Demonstration
// C++ program to demonstrate the use of virtual function
#include <iostream>
#include <string>
using namespace std;
class Animal {
private:
string type;
public:
// constructor to initialize type
Animal() : type("Animal") {}
// declare virtual function
virtual string getType() {
return type;
}
};
class Dog : public Animal {
private:
string type;
public:
// constructor to initialize type
Dog() : type("Dog") {}
string getType() override {
return type;
}
};
class Cat : public Animal {
private:
string type;
public:
// constructor to initialize type
Cat() : type("Cat") {}
string getType() override {
return type;
}
};
void print(Animal* ani) {
cout << "Animal: " << ani->getType() << endl;
}
int main() {
Animal* animal1 = new Animal();
Animal* dog1 = new Dog();
Animal* cat1 = new Cat();
print(animal1);
print(dog1);
print(cat1);
return 0;
}
Output
Animal: Animal
Animal: Dog
Animal: Cat
Here, we have used the virtual function getType() and an Animal pointer ani in order to avoid repeating the print() function in every class.
void print(Animal* ani) {
cout << "Animal: " << ani->getType() << endl;
}
In main(), we have created 3 Animal pointers to dynamically create objects of Animal, Dog and Cat classes.
// dynamically create objects using Animal pointers
Animal* animal1 = new Animal();
Animal* dog1 = new Dog();
Animal* cat1 = new Cat();
We then call the print() function using these pointers:
- When print(animal1) is called, the pointer points to an Animal object. So, the virtual function in Animal class is executed inside of print().
- When print(dog1) is called, the pointer points to a Dog object. So, the virtual function is overridden and the function of Dog is executed inside of print().
- When print(cat1) is called, the pointer points to a Cat object. So, the virtual function is overridden and the function of Cat is executed inside of print().
Key takeaway
A virtual function is a member function in the base class that we expect to redefine in derived classes.
Basically, a virtual function is used in the base class in order to ensure that the function is overridden. This especially applies to cases where a pointer of base class points to an object of a derived class.
#include <iostream>
using namespace std;
class base {
public:
virtual void vfunc() {
cout << "This is base's vfunc().\n";
}
};
class derived1 : public base {
public:
void vfunc() {
cout << "This is derived1's vfunc().\n";
}
};
class derived2 : public base {
public:
// vfunc() not overridden by derived2, base's is used
};
int main()
{
base *p, b;
derived1 d1;
derived2 d2;
// point to base
p = &b;
p->vfunc(); // access base's vfunc()
// point to derived1
p = &d1;
p->vfunc(); // access derived1's vfunc()
// point to derived2
p = &d2;
p->vfunc(); // use base's vfunc()
return 0;
}
An interface describes the behavior or capabilities of a C++ class without committing to a particular implementation of that class.
The C++ interfaces are implemented using abstract classes and these abstract classes should not be confused with data abstraction which is a concept of keeping implementation details separate from associated data.
A class is made abstract by declaring at least one of its functions as pure virtual function. A pure virtual function is specified by placing "= 0" in its declaration as follows −
class Box {
public:
// pure virtual function
virtual double getVolume() = 0;
private:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
};
The purpose of an abstract class (often referred to as an ABC) is to provide an appropriate base class from which other classes can inherit. Abstract classes cannot be used to instantiate objects and serves only as an interface. Attempting to instantiate an object of an abstract class causes a compilation error.
Thus, if a subclass of an ABC needs to be instantiated, it has to implement each of the virtual functions, which means that it supports the interface declared by the ABC. Failure to override a pure virtual function in a derived class, then attempting to instantiate objects of that class, is a compilation error.
Classes that can be used to instantiate objects are called concrete classes.
Consider the following example where parent class provides an interface to the base class to implement a function called getArea() −
#include <iostream>
using namespace std;
// Base class
class Shape {
public:
// pure virtual function providing interface framework.
virtual int getArea() = 0;
void setWidth(int w) {
width = w;
}
void setHeight(int h) {
height = h;
}
protected:
int width;
int height;
};
// Derived classes
class Rectangle: public Shape {
public:
int getArea() {
return (width * height);
}
};
class Triangle: public Shape {
public:
int getArea() {
return (width * height)/2;
}
};
int main(void) {
Rectangle Rect;
Triangle Tri;
Rect.setWidth(5);
Rect.setHeight(7);
// Print the area of the object.
cout << "Total Rectangle area: " << Rect.getArea() << endl;
Tri.setWidth(5);
Tri.setHeight(7);
// Print the area of the object.
cout << "Total Triangle area: " << Tri.getArea() << endl;
return 0;
}
When the above code is compiled and executed, it produces the following result −
Total Rectangle area: 35
Total Triangle area: 17
You can see how an abstract class defined an interface in terms of getArea() and two other classes implemented same function but with different algorithm to calculate the area specific to the shape.
An object-oriented system might use an abstract base class to provide a common and standardized interface appropriate for all the external applications. Then, through inheritance from that abstract base class, derived classes are formed that operate similarly.
The capabilities (i.e., the public functions) offered by the external applications are provided as pure virtual functions in the abstract base class. The implementations of these pure virtual functions are provided in the derived classes that correspond to the specific types of the application.
This architecture also allows new applications to be added to a system easily, even after the system has been defined.
Key takeaway
An interface describes the behavior or capabilities of a C++ class without committing to a particular implementation of that class.
The C++ interfaces are implemented using abstract classes and these abstract classes should not be confused with data abstraction which is a concept of keeping implementation details separate from associated data.
A class is made abstract by declaring at least one of its functions as pure virtual function.
In this section we will see what is early binding and what is late binding in C++. The binding means the process of converting identifiers into addresses. For each variables and functions this binding is done. For functions it is matching the call with the right function definition by the compiler. The binding is done either at compile time or at runtime.
This is compile time polymorphism. Here it directly associates an address to the function call. For function overloading it is an example of early binding.
#include<iostream>
using namespace std;
class Base {
public:
void display() {
cout<<" In Base class" <<endl;
}
};
class Derived: public Base {
public:
void display() {
cout<<"In Derived class" << endl;
}
};
int main(void) {
Base *base_pointer = new Derived;
base_pointer->display();
return 0;
}
In Base class
This is run time polymorphism. In this type of binding the compiler adds code that identifies the object type at runtime then matches the call with the right function definition. This is achieved by using virtual function.
#include<iostream>
using namespace std;
class Base {
public:
virtual void display() {
cout<<"In Base class" << endl;
}
};
class Derived: public Base {
public:
void display() {
cout<<"In Derived class" <<endl;
}
};
int main() {
Base *base_pointer = new Derived;
base_pointer->display();
return 0;
}
In Derived class
Key takeaway
In this section we will see what is early binding and what is late binding in C++. The binding means the process of converting identifiers into addresses. For each variables and functions this binding is done. For functions it is matching the call with the right function definition by the compiler. The binding is done either at compile time or at runtime.
REFERENCE
1 Object-Oriented Programming with C++ by E. Balaguruswamy. (Tata McGraw-Hill) 6th Edition and onwards
2. Object oriented Programming with C++- by SouravSahay (Oxford) 2ndedition