0% found this document useful (0 votes)
2 views

Virtual Function in CPP

The document explains virtual functions in C++, which are member functions declared in a base class and overridden in derived classes to achieve runtime polymorphism. It covers concepts such as early and late binding, pure virtual functions, friend classes, the 'this' pointer, and templates, including function and class templates. Additionally, it discusses the limitations of virtual functions and provides examples of function pointers and member function templates.

Uploaded by

bestfriend027087
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views

Virtual Function in CPP

The document explains virtual functions in C++, which are member functions declared in a base class and overridden in derived classes to achieve runtime polymorphism. It covers concepts such as early and late binding, pure virtual functions, friend classes, the 'this' pointer, and templates, including function and class templates. Additionally, it discusses the limitations of virtual functions and provides examples of function pointers and member function templates.

Uploaded by

bestfriend027087
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 13

Virtual Function in C++

A virtual function (also known as virtual methods) is a member function that is declared within a base class and is re-
defined (overridden) by a derived class. When you refer to a derived class object using a pointer or a reference to the
base class, you can call a virtual function for that object and execute the derived class’s version of the method.

• Virtual functions ensure that the correct function is called for an object, regardless of the type of reference (or
pointer) used for the function call.
• They are mainly used to achieve Runtime polymorphism.
• Functions are declared with a virtual keyword in a base class.
• The resolving of a function call is done at runtime.
Syntax
We can create a virtual function inside class using virtual keyword:
class Base
{
public:
virtual return_type
functionName()
{
// Function body
}
}

class Derived : public Base


{
public:
// Overriden virtual
// function of the base
// class
return_type functionName()
{
// Function body
}
}
Example
#include <iostream>
using namespace std;
class Base
{
public:
// Virtual function
virtual void display()
{
cout << "Base class display" << endl;
}
};
class Derived : public Base
{
public:
// Overriding the virtual
// function in the derived class
void display()
{
cout << "Derived class display" << endl;
}
};
int main()
{
Base* basePtr;
Derived derivedObj;
// Base class pointer pointing
// to derived class object
basePtr = &derivedObj;
// Calling the virtual function
basePtr->display();
return 0;
}
Early Binding and Late Binding
When a function is called in the code, binding decides which function gets executed based on the context such as the
type of object or the function signature. Binding happens at two levels:
• Early Binding: It happens when a function call is resolved during the program’s compilation. This makes it
faster because everything is decided early
• Late Binding: It happens with virtual functions where the exact function to call is decided at runtime,
depending on the actual object type. This is slower because the program has to figure it out while running.

Rules for Virtual Functions


The rules for the virtual functions in C++ are as follows:
1. Virtual functions cannot be static.
2. A virtual function can be a friend function of another class.
3. Virtual functions should be accessed using a pointer or reference of base class type to achieve runtime
polymorphism.
4. The prototype of virtual functions should be the same in the base as well as the derived class.
5. 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.
6. A class may have a virtual destructor, but it cannot have a virtual constructor.

Limitations of Virtual Functions


• Slower: The function call takes slightly longer due to the virtual mechanism and makes it more difficult for
the compiler to optimize because it does not know exactly which function is going to be called at compile
time.
• Difficult to Debug: In a complex system, virtual functions can make it a little more difficult to figure out
where a function is being called from.

Function Pointer to Member Function in C++


In C++, functions can be treated as objects with the help of function pointers. A function pointer to a member
function is a pointer that can refer to a member function of a specific class. Member functions differ from regular
functions because they are associated with an instance of a class, which means they have an implicit this pointer that
points to the object invoking the object. Following is the syntax to declare a function pointer to a member function:
Syntax
return_type (ClassName::*pointer_name)(argument_types) = &ClassName::member_function;

where:
• return_type: is the return type of the member function of the class.
• ClassName: is the name of the class to which the member function belongs.
• *pointer_name: is the name of the function pointer variable.
• argument_types: are the types of the arguments accepted by the member function.
• &ClassName::member_function: is the address of the member function being assigned to the function
pointer.
// C++ Program to Declare a Function Pointer to Member Function
#include <iostream>
using namespace std;
class MyClass
{
public:
int value;
// Constructor to initialize the member variable 'value'
MyClass(int val)
: value(val)
{
}
// Member function to add two integers and return the result
int add(int x, int y) { return x + y; }
};
int main()
{
// Create an instance of MyClass with the initial value of 10
MyClass obj(10);
// Declare a pointer to the member function 'add' of
// MyClass
int (MyClass::*ptrToMemberFunc)(int, int)
= &MyClass::add;
// Call the member function 'add' using the function
// pointer
int result = (obj.*ptrToMemberFunc)(20, 30);
// Print the result of the function call
cout << "Result from the member function: " << result << endl;
return 0;
}
Dynamic Binding in C++
Dynamic binding in C++ is a practice of connecting the function calls with the function definitions by avoiding
the issues with static binding, which occurred at build time. Because dynamic binding is flexible, it avoids the
drawbacks of static binding, which connected the function call and definition at build time. In simple terms, Dynamic
binding is the connection between the function declaration and the function call.

Pure Virtual Functions

A pure virtual function (or abstract function) in C++ is a virtual function for which we can have an
implementation, But we must override that function in the derived class, otherwise, the derived class will also become
an abstract class. A pure virtual function is declared by assigning 0 in the declaration.
class Test
{
// Data members of class
public:
// Pure Virtual Function
virtual void show() = 0;
/* Other members */
};
Friend Class in C++
In C++, friend functions and friend classes are concepts that allow certain functions or classes to access the
private and protected members of another class. These are useful concepts in such situations where you need to give
a function or another class access to internal data, while still keeping it hidden from the outside world.

A friend class can access private and protected members of other classes in which it is declared as a friend. It
is sometimes useful to allow a particular class to access private and protected members of other classes. Remember
one thing, Friendship is not mutual. If class A is a friend of B, then B doesn’t become a friend of A automatically.
We can declare a friend class in C++ by using the friend keyword.
Syntax:
friend class class_name; // declared in the base class
Example:

#include <iostream>
using namespace std;
class Geeks
{
private:
int private_variable;

protected:
int protected_variable;
public:
Geeks()
{
private_variable = 10;
protected_variable = 99;
}

// friend class declaration


friend class GFG;
};
// class GFG is declared as a friend
// inside class Geeks, therefore
// Class GFG can access private members
// of class Geeks.
class GFG
{
public:
void display(Geeks& t)
{
cout << "The value of Private Variable = "
<< t.private_variable << endl;
cout << "The value of Protected Variable = "
<< t.protected_variable;
}
};
int main()
{
Geeks g;
GFG fri;
fri.display(g);
return 0;
}
this pointer:

C++ uses a unique keyword called this to represent an object that invokes a member function. this is a pointer
that points to the object for which this function was called. For example, the function call A.max() will set the pointer
this to the address of the object A. The starting address is the same as the address of the first variable in the class
structure. This unique pointer is automatically passed to a member function when it is called. The pointer this acts as
an implicit argument to all the member functions.
Syntax:

// Reference to the calling object can be returned


Test& Test::func ()
{
//Someprocessing
return*this;
}

Consider the following


simple example:
class ABC
int a;
..
The private variable 'a' can be used directly inside a member function, like
a = 123;
We can also use the following statement to do the same job:
this->a = 123;
Since C++ permits the use of shorthand form a = 123, we have not been using the pointer this explicitly so
far. However, we have been implicitly using the pointer this when overloading the operators using member function.
Recall that, when a binary operator is overloaded using a member function, we pass only one argument to the
function. The other argument is implicitly passed using the pointer this. One important application of the pointer this
is to return the object it points to. For
example, the statement
return *this;
inside a member function will return the object that invoked the function. This statement assumes importance when
we want to compare two or more objects inside a member function and return the invoking object as a result. Example:

person & person :: greater(person & x)


if x.age > age
{
return x; // argument object
else
return *this; // invoking object
}
Example:
#include <iostream>
using namespace std;
// Class that uses this pointer
class A {
public:
int a;
A(int a)
{
// Assigning a of this object to
// function argument a
this->a = a;
}
void display()
{
// Accessing a of this object
cout << "Value: " << this->a;
}
};

int main()
{
// Checking if this works for the object
A o(10);
o.display();
return 0;
}
Templates in C++

C++ template is a powerful tool that allows you to write a generic code that can work with any data type. The
idea is to simply pass the data type as a parameter so that we don't need to write the same code for different data types.
For example, same sorting algorithm can work for different type, so rather than writing and maintaining multiple
codes, we can write one sort() and pass the datatype as a parameter.
Define Templates
Templates can be defined using the keywords "template" and "typename" as shown:
Syntax
template <typename A, typename B, ...>
entity_definition
The template keyword is used to define that the given entity is a template and typename keyword is used to
define template parameters which are nothing but types that will be provided when an instance is created. The
keyword typename can be replaced by keyword class anytime.
Example
template <class A, class B, ...>
entity_definition

Function Templates
In C++, templates allow us to write generic code for functions that can be used with different data types, and
this can be achieved by function templates. For example, we can write a function that gives you the maximum of two
numbers, but it can accept any number whether it is int, float, or double.
#include <iostream>
using namespace std;
// Function template definition
template <typename T> T myMax(T x, T y)
{
return (x > y) ? x : y;
}
int main()
{
// Call myMax for int
cout << myMax<int>(3, 7) << endl;
// call myMax for double
cout << myMax<double>(3.0, 7.0) << endl;
// call myMax for char
cout << myMax<char>('g', 'e');
return 0;
}
Class Templates
Class templates like function templates, are useful when a class defines something that is independent of the
data type. It is useful for classes like LinkedList, BinaryTree, Stack, Queue, Array, etc.
//Driver Code Starts{
#include <iostream>
using namespace std;
//Driver Code Ends }
// Defining class template
template <typename T> class Geek
{
public:
T x;
T y;
// Constructor
Geek(T val1, T val2) : x(val1), y(val2) {}
// Method to get values
void getValues()
{
cout << x << " " << y;
}
};
int main()
{
// Creating objects of Geek with
// different data types
Geek<int> intGeek(10, 20);
Geek<double> doubleGeek(3.14, 6.28);
// Access the templates values
intGeek.getValues();
cout << endl;
doubleGeek.getValues();
//Driver Code Starts{

return 0;
}
//Driver Code Ends
}
Member Function Templates in C++
In C++, member function templates allow you to define functions inside a class that are themselves templates
even if the class is not a template.
They are particularly useful when you want a class to operate normally, but have one or more member functions that
behave generically with respect to types.

1. Member Function Template in a Non-Template Class


#include <iostream>
using namespace std;
class Printer
{
public:
template <typename T>
void print(const T& data) {
cout << "Data: " << data << endl;
}
};
int main()
{
Printer p;
p.print(42); // int
p.print(3.14); // double
p.print("hello"); // const char*
}

2. Member Function Template in a Template Class

#include <iostream>
using namespace std;
template <typename T>
class Container
{
private:
T value;
public:
Container(T val) : value(val) {}
void show()
{
cout << "Value: " << value << endl;
}

template <typename U>


void compare(const U& other) {
cout << "Comparison result: " << (value == other ? "Equal" : "Not Equal") << endl;
}
};

int main()
{
Container<int> c(10);
c.show();
c.compare(10); // Same type
c.compare(10.0); // Different type, still works
}
Key Rules :
• A member function template must be defined inside the class or explicitly specialized if defined outside.
• Unlike regular member functions, template member functions are not virtual (can’t be overridden polymorphically).
• Member function templates can’t be used as constructors, but you can use them in copy/move constructors via perfect forwarding
(advanced topic).
Template Variables
A template variable is a variable that can work with any type specified when the variable is used, similar to
how we use templates for functions or classes.
Syntax:
template <typename T> constexpr T pi = T(3.14159);
In the above statement, pi is the template variable. We use constexpr with the template variable because it
ensures that the variable is a constant expression and is evaluated at compile time rather than at runtime
Example
#include <iostream>
using namespace std;
// Template variable with constexpr
template <typename T> constexpr T pi = T(3.14159);
int main()
{
// Using pi with different types
cout << "Pi as float: " << pi<float> << endl;
cout << "Pi as double: " << pi<double>;
return 0;
}
There are three main kinds of template arguments:
1. Type Template Arguments
These are the most common. You pass a type to the template.
template <typename T>
void print(const T& value)
{
std::cout << value << std::endl;
}
int main()
{
print<int>(42); // T = int
print<std::string>("Hi"); // T = std::string
}
2. Non-Type Template Arguments
These are constant values passed to a template (like integers, pointers, etc.). The values must be compile-time
constants.
Example:
template <int N>
void repeat()
{
for (int i = 0; i < N; ++i)
std::cout << "Repeat!" << std::endl;
}
int main()
{
repeat<3>(); // Prints "Repeat!" 3 times
}
3. Template Template Arguments
These are used when a template takes another template as a parameter.
Example:
#include <iostream>
#include <vector>
template <template <typename, typename> class ContainerType>
class Wrapper
{
public:
ContainerType<int, std::allocator<int>> data;
void add(int value)
{
data.push_back(value);
}
void print()
{
for (int val : data)
std::cout << val << " ";
std::cout << std::endl;
}
};

int main()
{
Wrapper<std::vector> w;
w.add(1);
w.add(2);
w.print(); // Output: 1 2
}

Function Overloading Function Templates

Function overloading allows multiple


Function templates define a generic function that
functions with the same name but different
works with any data type.
parameters (number or types).

Different functions with the same name


A single template function can work with any data
must have different parameter types,
type by using type parameters.
number of parameters, or both.

Each overloaded function is explicitly A function template is defined once and can be used
defined for specific types. for multiple types.

Requires writing separate functions for each No code duplication, as the same template is used for
type. various types.

Used when you need to perform the same


Used when the same function logic applies to different
task on different data types, but with
types, and type is deduced or explicitly provided.
different implementations.
Exception Handling in C++
In C++, exceptions are unexpected problems or errors that occur while a program is running. For example, in
a program that divides two numbers, dividing a number by 0 is an exception as it may lead to undefined errors.
The process of dealing with exceptions is known as exception handling. It allows programmers to make the
program ready for any errors that may happen during execution and handle them gracefully so that it keeps running
without errors.
try-catch Block
C++ provides an inbuilt feature for handling exceptions using try and catch block. It is an exception handling
mechanism where the code that may cause an exception is placed inside the try block and the code that handles the
exception is placed inside the catch block.
try {
// Code that might throw an exception
}
catch (ExceptionType e) {
// exception handling code
}
When an exception occurs in try block, the execution stops, and the control goes to the matching catch block
for handling.
Throwing Exceptions
Throwing exception means returning some kind of value that represent the exception from the try block. The
matching catch block is found using the type of the thrown value. The throw keyword is used to throw the exception.

try
{
throw val
}
catch (ExceptionType e)
{
// exception handling code
}
There are three types of values that can be thrown as an exception:
• Built-in Types
• Standard Exceptions
• Custom Exceptions
Throwing Built-in Types
Throwing built-in types is very simple but it does not provide any useful information. For example,
#include <bits/stdc++.h>
using namespace std;
int main()
{
int x = 7;
try
{
if (x % 2 != 0)
{
// Throwing int
throw -1;
}
}

// Catching int
catch (int e)
{
cout << "Exception Caught: " << e;
}
return 0;
}
Here, we have to make decision based on the value thrown. It is not much different from handling errors using
if else. There is a better technique available in C++. Instead of throwing simple values, we can throw objects of classes
that contains the information about the nature of exception in themselves.
Throwing Standard Exceptions
Standard exceptions are the set of classes that represent different types of common exceptions. All these classes
are defined inside <stdexcept> header file and mainly derived from std::exception class which act as the base class
for inbuilt exceptions. The below image shows standard exceptions hierarchy in C++:
These exceptions are thrown by C++ library components so we should know how to handle them.
The what() method is present in every standard exception to provide information about the exception itself.
For example, the vector at() method throws an out_of_range exception when the element with given index
does not exists.
#include <bits/stdc++.h>
using namespace std;
int main()
{
vector<int> v = {1, 2, 3};
try
{
// Accessing out of bound element
v.at(10);
}
catch (out_of_range e) {
cout << "Caught: " << e.what();
}
return 0;
}
Throwing Custom Exceptions
When the standard exceptions cannot satisfy our requirement, we can create a custom exception class. It is
recommended to inherit standard exception in this class to provide seamless integrity with library components though,
it is not compulsory.
Catching Exceptions
As already told, the catch block is used to catch the exceptions thrown in the try block. The catch block takes one
argument, which should be of the same type as the exception.
catch (exceptionType e)
{
...
}
Here, e is the name given to the exception. Statements inside the catch block will be executed if the exception
of exceptionType is thrown in try block.
Catching Multiple Exceptions
There can be multiple catch blocks associated with a single try block to handle multiple types of exceptions.
For Example,
try
{
// Code that might throw an exception
}
catch (type1 e)
{
// executed when exception is of type1
}
catch (type2 e)
{
// executed when exception is of type2
}
catch (...)
{
// executed when no matching catch is found
}
In the above code, the last statement catch(...) creates a catch-all block which is executed when none of the above
catch statements are matched. For example,
#include <bits/stdc++.h>
using namespace std;
int main()
{
// Code that might throw an exception
try {
int choice;
cout << "Enter 1 for invalid argument, "
<< "2 for out of range: ";
cin >> choice;
if (choice == 1)
{
throw invalid_argument("Invalid argument");
}
else if (choice == 2)
{
throw out_of_range("Out of range");
}
else
{
throw "Unknown error";
}

}
// executed when exception is of type invalid_argument
catch (invalid_argument e)
{
cout << "Caught exception: " << e.what() << endl;
}
// executed when exception is of type out_of_range
catch (out_of_range e)
{
cout << "Caught exception: " << e.what() << endl;
}
// executed when no matching catch is found
catch (...) {
cout << "Caught an unknown exception." << endl;
}
return 0;
}
Catch by Value or Reference
Just like function arguments, the catch block can catch exceptions either by value or by reference. Both of the
methods have their own advantage.
Catch by Value
Catching exceptions by value creates a new copy of the thrown object in the catch block. Generally, the
exceptions objects are not very large so there is not much overhead of creating copies.
#include <bits/stdc++.h>
using namespace std;
int main()
{
try
{
throw runtime_error("This is runtime exception");
}

// Catching by value
catch (runtime_error e) {
cout << "Caught: " << e.what();
}
return 0;
}
Catch by Reference
Catch by reference method just pass the reference to the exception thrown instead of creating a copy. Although it
reduces the copy overhead, it is not the primary advantage of this method. The main advantage of this method is in
catching polymorphic exception types. For example,
#include <bits/stdc++.h>
using namespace std;
int main()
{
try
{
throw runtime_error("This is runtime exception");
}

// Catching by value
catch (exception& e)
{
cout << "Caught: " << e.what();
}
return 0;
}

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy