C++ Concept Refresher - CSU1287 - CSE 2026 - Shoolini U

Revision of Concepts in C++

Inheritance

Inheritance is a fundamental concept in OOP that allows you to define a new class based on an existing one. The new class (called the derived class or child class) inherits the properties and methods of the base class (or parent class).

#include <iostream>
using namespace std;

class Animal {  // Base class
public:
   void eat() {
      cout << "I can eat!" << endl;
   }
};

class Dog : public Animal {  // Derived class
public:
   void bark() {
      cout << "I can bark! Woof!" << endl;
   }
};

int main() {
   Dog dog;
   dog.eat();  // Inherited from Animal
   dog.bark(); // Specific to Dog
   return 0;
}

Abstraction

Abstraction involves creating simple, abstract models of more complex systems by encapsulating the complex details and exposing only what's necessary. In C++, we can use classes and interfaces for abstraction.
Consider an example of a simple Computer class:

#include <iostream>
using namespace std;

class Computer {
public:
   void PowerOn() {
      cout << "Computer is turned on!" << endl;
   }

   void PowerOff() {
      cout << "Computer is turned off!" << endl;
   }
};

int main() {
   Computer myPC;
   myPC.PowerOn();
   myPC.PowerOff();
   return 0;
}

Here, the internal details of how a computer turns on or off are hidden. We just need to know about PowerOn() and PowerOff() methods.

Polymorphism

Polymorphism is the ability of an object to take on many forms. The most common use of polymorphism in OOP occurs when a parent class reference is used to refer to a child class object.

#include <iostream>
using namespace std;

class Animal {  // Base class
public:
   virtual void sound() {
      cout << "Animals make sounds" << endl;
   }
};

class Dog : public Animal {  // Derived class
public:
   void sound() {
      cout << "Dogs bark!" << endl;
   }
};

int main() {
   Animal* animal = new Dog();
   animal->sound(); // Outputs: Dogs bark!
   delete animal;
   return 0;
}

Here, sound() function in Dog class is overriding the sound() function of Animal class. This demonstrates polymorphism as we use a base class pointer to refer to a derived class object and call the correct version of sound().

Encapsulation

Encapsulation is an Object-Oriented Programming principle that binds together the data and functions that manipulate the data, and keeps them safe from outside interference and misuse. In simpler words, it is the wrapping up of data and functions into a single unit called class.
Here's a simple example using a BankAccount class:

#include <iostream>
using namespace std;

class BankAccount {
private:
    double balance;  // Private attribute

public:
    BankAccount(double bal) {
        if (bal > 0)
            balance = bal;
        else
            balance = 0.0;
    }

    void deposit(double amount) {
        balance += amount;
    }

    void withdraw(double amount) {
        if (balance - amount >= 0)
            balance -= amount;
        else
            cout << "Insufficient balance!" << endl;
    }

    double getBalance() { 
        return balance; 
    }
};

int main() {
    BankAccount account(100.0);
    account.deposit(50.0);
    account.withdraw(20.0);
    cout << "Account balance: INR " << account.getBalance() << endl; // Outputs: Account balance: INR 130.0
    return 0;
}

In this example, the BankAccount class encapsulates data (balance) and functions (deposit, withdraw, and getBalance). The balance attribute is private, meaning it cannot be accessed directly from outside the class; instead, it must be accessed through the public functions. This way, we ensure the balance cannot be changed arbitrarily, thus maintaining data integrity.

Member Functions

Member functions (also known as methods) in C++ are functions that belong to objects in a class. They operate on an object and can access the data members and functions of the class to which they belong.
Here's a simple example:

#include <iostream>
using namespace std;

class Rectangle {
private:
    double width;
    double height;

public:
    void setValues(double w, double h) {  // Member function
        width = w;
        height = h;
    }

    double area() {  // Member function
        return width * height;
    }
};

int main() {
    Rectangle rect;
    rect.setValues(4.0, 2.0);
    cout << "Area: " << rect.area() << endl;  // Outputs: Area: 8
    return 0;
}

In this example, Rectangle is a class with two private data members: width and height. The class has two member functions:

In main(), we create an object rect of type Rectangle. We use the setValues() member function to set the values of width and height, and then we call the area() member function to calculate the area of the rectangle.

Access to member functions is controlled by their access specifiers (public, private, protected). Here, both member functions are public, so they can be accessed from outside the class.

Constructors and its types

In C++, a constructor is a special type of member function that gets called whenever an object of its associated class is created. Constructors have the same name as the class and don't have a return type.
Here are the types of constructors in C++:

Please note that the system automatically provides a default and a copy constructor if you don't provide them, but sometimes it's necessary to define them yourself, particularly when working with dynamic memory or resources like file handles.

Access Specifiers

Access specifiers in C++ are keywords that define how to access the members (functions and variables) of a class. There are three types of access specifiers:

Here's a simple example demonstrating these access specifiers:

#include<iostream>
using namespace std;

class MyClass {
public:
    int publicVar;

private:
    int privateVar;

protected:
    int protectedVar;
};

class ChildClass : public MyClass {
public:
    void accessProtected() {
        protectedVar = 10;  // Allowed, as protected members are accessible in child classes
        cout << "Protected Var: " << protectedVar << endl;
    }
};

int main() {
    MyClass obj;
    obj.publicVar = 5;  // Allowed
    // obj.privateVar = 5;  // Not allowed, gives a compilation error
    // obj.protectedVar = 5;  // Not allowed, gives a compilation error

    ChildClass childObj;
    childObj.accessProtected();  // Allowed
    return 0;
}
In this code:

Scope Resolution Operator

The Scope Resolution Operator (::) in C++ is used to define a function outside a class or to access a global variable within a scope where a local variable with the same name exists.

Here's an example of defining a function outside of a class using ::

#include <iostream>
using namespace std;

class MyClass {
public:
    void myFunction();
};

// Defining myFunction outside the class using Scope Resolution Operator
void MyClass::myFunction() {
    cout << "Function called" << endl;
}

int main() {
    MyClass obj;
    obj.myFunction();  // Outputs: Function called
    return 0;
}

In this example, myFunction is declared inside MyClass but defined outside the class using the scope resolution operator ::.

Here's an example of using :: to access a global variable when a local variable with the same name exists:

#include <iostream>
using namespace std;

int var = 10;  // Global variable

int main() {
    int var = 20;  // Local variable
    cout << "Local var: " << var << endl;  // Outputs: Local var: 20
    cout << "Global var: " << ::var << endl;  // Outputs: Global var: 10
    return 0;
}

In this example, the local variable var shadows the global variable var within the main() function. To access the global var within main(), we use the scope resolution operator ::.

Virtual Function

A virtual function, declared with the keyword 'virtual' in a base class, is designed for redefinition in derived classes. This mechanism supports runtime polymorphism in C++, allowing interchangeability of base and derived class objects, ensuring the correct function call.

Let us learn about it with an example:

#include <iostream>
using namespace std;

class Base {
public:
    virtual void show() {
        std::cout << "In Base" << endl;
    }
};

class Derived : public Base {
public:
    void show() override {
        std::cout << "In Derived" << endl;
    }
};

int main() {
    Base* basePtr = new Derived();
    basePtr->show(); // Outputs: "In Derived", due to the 'virtual' keyword
    delete basePtr; 

    return 0;
}

Here, new is used to dynamically allocate memory for a Derived pointer object on the heap, and return a pointer to the start of it. This pointer is stored in basePtr. When basePtr->show() is called it outputs "In Derived". This is due to the virtual keyword allowing for late (or dynamic) binding. delete is used to deallocate (or free up) the memory that was previously allocated with new. After this line, the memory where the Derived object was stored is freed up and basePtr should not be used.

Early Binding and Late Binding

Early Binding (or Static Binding) and Late Binding (or Dynamic Binding) refer to when the association of a function call to a function body is made.

Early Binding happens at compile-time. The association of a function to its function call is made before the program runs. On the other hand, Late Binding occurs at runtime, where the compiler determines the type of an object at runtime and then binds the function call to its definition.

#include <iostream>
using namespace std;

class Shape {
public:
    virtual void draw() { //early binding
        cout << "Drawing a shape.\n";
    }
};

class Circle: public Shape {
public:
    void draw() { //late binding (using function overriding)
        cout << "Drawing a circle.\n";
    }
};

int main() {
    Shape shape;
    Circle circle;
    
    shape.draw(); // Outputs: Drawing a shape. (Early binding)
    circle.draw(); // Outputs: Drawing a circle. (Late binding)
    return 0;
}

Here, when you call draw() on shape, it knows at compile time it's going to call Shape::draw(). That's Early Binding. When you call draw() on circle, because draw() is a virtual function and circle is an instance of the derived class Circle, it doesn't decide until runtime which draw() it will call. This is Late Binding. Lets look at another example.

#include <iostream>
using namespace std;

class Shape {
public:
    virtual void draw() { // This function is now virtual!
        cout << "Drawing a shape.\n";
    }
};

class Circle: public Shape {
public:
    void draw() override { // This function overrides the base function!
        cout << "Drawing a circle.\n";
    }
};

int main() {
    Shape* shape = new Shape();
    Shape* circle = new Circle(); // circle is a Shape pointer that points to a Circle object
    
    shape->draw(); // Outputs: Drawing a shape. (Late binding, but since it's a Shape object, Shape's draw() is called)
    circle->draw(); // Outputs: Drawing a circle. (Late binding)
    
    delete shape;
    delete circle;

    return 0;
}

Operator Overloading

Operator Overloading is a compile-time polymorphism concept that allows you to redefine the way an operator works for user-defined types such as classes and structures. You can redefine or overload most of the built-in operators available in C++.

#include <iostream>

class Counter {
    int count = 0;

public:
    void operator++() {
        count++;
    }

    int getCount() const {
        return count;
    }
};

int main() {
    Counter c;
    ++c;
    std::cout << c.getCount() << std::endl;
    return 0;
}

This code demonstrates a simple counter using operator overloading in C++. It defines a class called Counter with a private member variable count initialized to 0. The class overloads the pre-increment operator (++) to increment the count by 1.

In the main function, an instance of the Counter class is created, and the overloaded ++ operator is used to increment the count. The current count value is then printed using the getCount member function.

The code showcases how operator overloading can be used to redefine the behavior of operators, providing custom functionality for user-defined types. In this case, it allows the Counter object to be incremented in a natural and intuitive way.

Friend Function

A friend function in C++ is a function that has the right to access all private and protected members (variables and functions) of the class, even though it is not itself a member function of that class. This helps enhance the flexibility of the code where certain functions require direct access to class members.
Here's a simple example of using a friend function to add two numbers:

#include <iostream>
using namespace std;

class Number {
    int num;
public:
    Number(int n) : num(n) {}

    // Declaration of friend function
    friend int addFive(Number n);
};

// Definition of friend function
int addFive(Number n) {
    return n.num + 5;  // can access private member 'num' directly
}

int main() {
    Number n(7);
    cout << addFive(n);  // Outputs: 12
    return 0;
}

In this example, addFive() is a friend function to class Number. Even though addFive() isn't a member function of Number, it can directly access the private data member num. This enables addFive() to add 5 to the value of num.

Friend Class

A friend class in C++ is a class whose members have the right to access all private and protected members of another class. It enhances the flexibility of the code where certain classes need direct access to another class's members.
Here's a simple example to demonstrate a friend class:

#include <iostream>
using namespace std;

class ClassB; // Forward declaration

class ClassA {
private:
    int numA;

public:
    ClassA() : numA(123) {}

    friend class ClassB;  // ClassB is a friend class of ClassA
};

class ClassB {
public:
    void showA(ClassA& a) {
        // Since ClassB is a friend of ClassA, it can access private members of ClassA
        cout << "ClassA::numA: " << a.numA << endl;
    }
};

int main() {
    ClassA a;
    ClassB b;
    b.showA(a);  // Outputs: ClassA::numA: 123
    return 0;
}

In this code, ClassB is a friend of ClassA. This means that ClassB can access the private and protected members of ClassA. In the showA method of ClassB, it directly accesses the private data member numA of ClassA.

Pointers

A pointer in C++ is a variable that stores the memory address of another variable. Pointers are used for dynamic memory allocation and efficient manipulation of data.

#include <iostream>
using namespace std;

int main() {
    int num = 10;  // Declare an integer variable
    int* ptr = &num ;  // Declare a pointer variable and store the address of num

    cout << "Value of num: " << num << endl;
    cout << "Address of num: " << &num << endl;
    cout << "Value of ptr (address of num): " << ptr << endl;
    cout << "Value that ptr points to (value of num): " << *ptr << endl;

    return 0;
}

In this example:

  1. num is an integer variable with a value of 10.
  2. ptr is a pointer variable that holds the memory address of num. We get the address of num using the address-of operator &.
  3. &num gives the memory address of num.
  4. ptr gives the memory address stored in the pointer ptr (which is the address of num).
  5. *ptr gives the value at the memory address stored in ptr (which is the value of num). The * here is used as the dereference operator, not for multiplication.
  6. Remember, the actual memory addresses on your system will be different, as they are allocated by your system at runtime.

Pointers in classes and objects

Pointers can certainly be used with classes and objects. A pointer to a class is not much different from a pointer to an integer or any other variable. The most significant difference is how to access the members of the object (member variables and methods).
To access members of a class using a pointer, you need to use the arrow operator (->).
Here's a simple example:

#include <iostream>
using namespace std;

class MyClass {
public:
    int myVar;

    void myFunc() {
        cout << "This is inside the function!" << endl;
    }
};

int main() {
    MyClass obj;
    obj.myVar = 10;

    MyClass *ptr = &obj;  // Declare a pointer to obj

    cout << "Value of myVar: " << ptr->myVar << endl;  // Access myVar through pointer

    ptr->myFunc();  // Call myFunc() through pointer

    return 0;
}

In this code:

  1. We declare an object obj of MyClass.
  2. We declare a pointer ptr to MyClass, and make it point to obj.
  3. To access the member variable myVar and the member function myFunc(), we use the arrow operator ->.
  4. Please note that when working with pointers, it's important to ensure that they are always initialized and that you don't go beyond the bounds of allocated memory, as this can lead to undefined behavior or program crashes.