In the previous part of this blog, we discussed the fundamentals of object-oriented programming in C++. We also explored using objects as arguments and return types in functions. Additionally, we delved into the concepts of static, mutable, and constant class members.

In this subsequent article, we will explore the nuances of friend classes and friend functions and delve into operator overloading. Additionally, we'll discuss the various forms of inheritance, member visibility, and function overriding within the C++ programming language.

Friend Functions

A friend function is a non-member function of a class that possesses access to all the private and protected members of that class. Instead of being a class member, it is considered an external function with special access privileges.

Syntax:

class class­name {
    ...
    friend return­type function(arguments); 
    
};

return­type function(arguments) { 
    //body of function
}

The syntax of declaring a Friend Function in a

ℹ️
Friend functions can be declared anywhere within the class.

Example Code:

#include <iostream>
using namespace std;
const unsigned int SIZE = 10;
class Num 
{
    int n[SIZE]; 
    
public:
    void input()
    {
        cout << "Enter the elements:"; 
        for(int i=0; i<SIZE; i++)
        	cin >> n[i];
    }
    
    friend float average(Num);
};

float average(Num n1)
{ 
    float sum=0.0;
    for(int i=0; i<SIZE; i++)
    sum += n1.n[i]; return sum/SIZE;
}

main() 
{
    Num n1; float avg;
    n1.input();
    avg = average(n1);
    cout << "average = " << avg << endl;
    return 0; 
    
}

A program to create a global function that calculates the average of a list of 10 numbers stored within a member.

The output:

Enter the elements:1
2
3
4
5
6
7
8
9
10
average = 5.5

Friend As A Bridge Function

Friend functions can bridge two or more classes, allowing them to access each other's private and protected members. To achieve this, you need to declare the same function as a friend in the classes that need to be linked, as shown in the example below:

Example code:

#include <iostream> 
using namespace std;
class ObjB;

class ObjA {
    int x; 
    
public:
    void input(){
        cout << "Enter value of x: "; cin >> x;
    }
    void display(){
        cout << "Value of x is " << x << endl;
    }
    friend void swap(ObjA&, ObjB&); 
    
};

class ObjB {
    int a; 
public:
    void input(){
        cout << "Enter value of a: ";
        cin >> a; 
        
    }
    void display(){
        cout << "Value of a is " << a << endl;
    }
    friend void swap(ObjA&, ObjB&); 
    
};

void swap(ObjA& a, ObjB& b){ 
    int tmp = a.x;
    a.x = b.a;
    b.a = tmp; 
}

main() {
    ObjA a1; 
    ObjB b1;
    a1.input(); 
    b1.input();
    swap(a1, b1); 
    a1.display(); 
    b1.display();
    return 0; 
}

A program to swap the private data of two different classes

The output:

Enter value of x: 10
Enter value of a: 20
Value of x is 20
Value of a is 10

Member Function of a Class as a Friend of Another

Member functions of one class can be declared as friend functions in another class. In such cases, you must use their fully qualified name during declaration.

Example Code:

#include <iostream> 
using namespace std; 
class B;
class A {
    int a; 
public:
    void input(){
        cout << "Enter the value of a :"; cin >> a ;
    }
    void mult(B t); 
    
};
class B {
    int b; 
public:
    void input(){
        cout << "Enter the value of b:"; cin >> b;
    }
    friend void A::mult(B t); 
    
};
void A::mult(B t){
    cout << a << "*" << t.b << "=" << a*t.b << endl;
}
main() {
    A a;
    B b; 
    a.input(); 
    b.input(); 
    a.mult(b);
    return 0; 
    
}

A C++ program to multiply two numbers using a member function of one class as a friend function of another class

The output:

Enter the value of a :10
Enter the value of b:4
10*4=40

Friend Class

There may be scenarios where you need all the member functions of one class to be declared as friends of another class. Instead of making each function a friend individually, you can declare the entire class as a friend.

Example Code:

#include<iostream>
using namespace std;
class ABC; 
class XYZ {
    int x; 
public:
    friend class ABC;
};
class ABC {
    int a; 
public:
    void getdata(XYZ &o1) {
        cout << "Enter the value of a:"; cin >> a;
        cout << "Enter the value of x:"; cin >> o1.x;
    }
    void sum(XYZ &o1) {
        cout << "The sum is:" << a+o1.x << endl; 
        
    }
    void product(XYZ &o1) {
        cout << "The product is:" << a * o1.x << endl;
    }
};
int main() {
    ABC obj1;
    XYZ obj2; 
    obj1.getdata(obj2);
    obj1.sum(obj2); 
    obj1.product(obj2);
    return 0; 
    
}

A C++ program to demonstrate friend classes

The output:

Enter the value of a:10
Enter the value of x:20
The sum is:30
The product is:200

Operator Overloading

Operator overloading in C++ allows you to give user-defined data types the ability to mimic the behavior of built-in data types. It involves defining the actions and behaviors of various operators for custom data types, which can make your code more intuitive and expressive. This means that you can use operators like +, -, *, /, and many others with your custom data types just like you would with built-in data types, as long as you provide appropriate definitions for those operations. This feature enhances the flexibility and usability of C++ when working with user-defined data types.

In C++, all operators can be overloaded except for the following:

  • sizeof operator
  • Member Operator (.)
  • Pointer to Member Operator (.*)
  • Scope Resolution Operator (::)
  • Conditional Operator (?.)

Syntax

return type className:: operator op(arglist){
    //function body
}

Rules for Operator Overloading:

  • Only existing operators can be overloaded; new operators cannot be created.
  • Overloaded operators must have at least one operand of a user-defined type.
  • Overloaded operators follow the syntax rules of the original operators; they cannot be overridden.
  • The operators mentioned above can not be overloaded.

Unary Operator Overloading

Unary operator overloading in C++ involves overloading operators that work on a single operand. When you overload unary operators, you define how they should behave when applied to instances of your user-defined data types.

Unary operators include operators like ++ (pre-increment, post-increment), – (pre-decrement, post-decrement), -, and !, among others. By defining the appropriate member functions for these operators in your class, you can specify how they should work when used with objects of that class, similar to how built-in data types work with these operators.

return­type class­name::operator OP(){
    // body of operator function 
}

Example Code:

# include <iostream> 
using namespace std; 
class Stud
{
    int a; 
public:
    void input() {
        cout <<"\n Enter the value of a:";
        cin >> a; 
    }
    void display() {
        cout<<"\n The value of a is:" << a << endl; 
        
    }
    Stud operator -(); 
    
};
Stud Stud::operator -() {
    Stud temp; 
    temp.a= -a; 
    return temp;
}

int main() {
    Stud S1, S2;
    S1.input();
    S1.display();
    S2 =-S1; // S2=S1.Operator ­(); 
    S1.display();
    S2.display(); 
    return 0;
}

A program to overload the - operator

The output:

Enter the value of a:10
The value of a is:10

 The value of a is:10

 The value of a is:-10

Unary Operator Overloading Using Friend Function


Example code:

#include <iostream> 
using namespace std;
class Complex {
    int r, m; 
public:
    void input(){
        cout << "Enter real and imaginary part " << endl; 
        cin >> r >> m;
    }
    void display(){
        cout << r << "+" << m << "i" << endl; 
        
    }
    friend Complex operator -- (Complex&); 
    
};
Complex operator -- (Complex& c){ 
    Complex temp;
    temp.r = c.r-1; 
    temp.m = c.m-1; 
    return temp;
    }
main() {
    Complex c1, c2; 
    c1.input();
    c2 = --c1; 
    c2.display();
    return 0;
}

A program to overload -- operator using a friend function

The output:

Enter real and imaginary part 
10
5
9+4i

Binary Operator Overloading

Binary operator overloading in C++ involves overloading operators that work on two operands. This allows you to define how binary operators should behave when applied to instances of your user-defined data types. By overloading these operators, you can customize the behavior of your class objects when used with binary operators. Binary operators include common mathematical operators such as +, -, *, /, as well as comparison operators like ==, !=, <, >, and more.

By providing appropriate member functions for these operators in your class, you specify how they should work when used with objects of that class, just like how built-in data types interact with these operators.

Syntax:

return_type classname::operator OP(argument){
    statements; 
}

Example code:

#include <iostream> 
using namespace std;
class Complex {
    int r, m; 
public:
    void input(){
        cout << "Enter real and imaginary part " << endl; 
        cin >> r >> m;
    }
    void display(){
        cout << r << "+" << m << "i" << endl; 
        
    }
    Complex operator + (int); 
        
};
Complex Complex::operator + (int a){ 
    Complex temp;
    temp.r = r+a; 
    temp.m = m+a; 
    return temp;
}
main() {
    Complex c1, c2; 
    c1.input();
    c2 = c1 + 2; 
    c2.display();
    return 0; 
    
}

A C++ program to overload the + operator

The output of the above code:

Enter real and imaginary part 
10
5
12+7i

Binary operator using friend function

In binary operator overloading using a friend function, you can control the order of operands. The first argument serves as the left operand, while the second argument serves as the right operand.

Example Code:

#include <iostream> 
using namespace std;
class Complex {
    int r, m; 
public:
    void input(){
        cout << "Enter real and imaginary part " << endl; 
        cin >> r >> m;
    }
    void display(){
        cout << r << "+" << m << "i" << endl; 
        
    }
    friend Complex operator + (Complex, int); 
        
};
Complex operator + (Complex c, int a)
{ 
    Complex temp;
    temp.r = c.r+a; 
    temp.m = c.m+a; 
    return temp;
}
main() {
    Complex c1, c2; 
    c1.input();
    c2 = c1 + 2; 
    c2.display();
    return 0; 
    
}

A C++ program to overload the + operator using a friend function

Output:

Enter real and imaginary part 
5 10
7+12i

Inheritance

Inheritance is a fundamental concept in object-oriented programming, allowing the creation of a new class by deriving it from an existing one. With inheritance, a child class can inherit the attributes and behaviors of a parent class, providing the benefit of code reusability. Additionally, a child class can enhance its inherited properties and methods with its own distinct characteristics.

Need for Inheritance

  • Allows the re-usability of code
  • Addition of new features and functionality to the inherited property
  • Creates better connections among different classes.
  • Achieve overriding of the virtual and abstract base function
  • Organization of code in a logical and structural manner

Base and Derived Classes

Inheritance in C++ is based on the concept of a base class with attributes and methods, serving as the foundation, and derived classes, also known as child classes, inheriting these attributes and methods. Importantly, C++ allows a class to inherit from multiple base or parent classes.

Access Specifier

There are three different access modes in c++.

Public Access- Every other class can access the public members of the class.

Protected Access - Only a class derived from this class can access a protected member.

Private Access- Private members can only be accessed inside the class.

Derived Class Declaration

The class name is followed by colon(:), visibility mode and base class name, respectively. Visibility mode may be private, public or protected.

ℹ️
By default the visibility mode is private

Syntax:

class derived­class­name : visibility­mode base­class­name {
    // members
};

For inheritance from multiple classes, commas are used as shown below:

class derived­class­name : visibility­mode base­class­name,, visibility base2­name {
    // members
};

Visibility Mode

Visibility mode controls the access modifier to which inherited members of base class are placed in derived mode.

Notably, private members of the base class are never inherited. In public visibility mode, public members are inherited as public members in the derived class, and protected members are inherited as protected members. Conversely, private visibility mode results in the inheritance of both public and protected members as private access specifiers.

Member function Overriding

Function overriding occurs when a derived class redeclares a member function that already exists in the visible section of the base class.

Example Code:

#include<iostream> 
using namespace std;
class Base1{ 
    protected:
    int a; 
public:
    void input(){
        cout<<"enter value to a of Base1:" <<endl; 
        cin >> a;
    }
    void display(){
        cout<<"the a of Base1 is:" << a << endl; 
        
    }
};
class Base2{ 
    protected:
    int a; 
    public:
    void input(){
        cout<<"enter value to a of Base2" << endl; 
        cin >> a;
    }
    void display(){
        cout<<"the a of Base2 is:" << a << endl; 
        
    }
};
class Derived: public Base1, public Base2{ int c;
    public:
    void input(){
        cout<<"enter the value of c:" << endl;
        cin >> c; 
        
    }
    void display(){ 
        Base1::display();
        Base2::display();
        cout<<"the value of c is:" << c << endl;
        cout<<"the sum is:" << Base1::a + c + Base2::a << endl;
    } 
    
};
int main(){ 
    Derived D1;
    // D1.Derrived::input();
    D1.Base1::input();
    D1.Base2::input();
    D1.input();
    cout<<"displaying the taken value:" << endl;
    D1.display();
    return 0;
}

A C++ program demonstrating function overriding

The output:

enter value to a of Base1:
10
enter value to a of Base2
20
enter the value of c:
30
displaying the taken value:
the a of Base1 is:10
the a of Base2 is:20
the value of c is:30
the sum is:60
Thank you for reading this article. Please leave a comment below if you liked it.