Programming Pandit

c/c++/c#/Javav/Python


Latest Update

Monday, September 14, 2026

September 14, 2026

Constructors and Their Types in C++

 

Constructors and Their Types in C++

A constructor is a special member function of a class that is automatically invoked when an object of that class is created. Its primary purpose is to initialize the object.

Constructors are fundamental to object-oriented programming because they ensure that an object starts its lifetime in a valid and meaningful state.

Image

Image

Image

1. What is a Constructor?

A constructor is a special member function having the same name as the class.

For example:

class Student
{
public:
    Student()
    {
        cout << "Constructor called";
    }
};

When an object is created:

Student s;

the constructor is automatically called.

        Object Creation
              |
              ↓
        Student s;
              |
              ↓
     Student() constructor
              |
              ↓
       Object initialized

Unlike an ordinary member function, a constructor:

  • Has the same name as the class.

  • Has no return type, not even void.

  • Is called automatically when an object is created.

  • Is normally used to initialize data members.

  • Can be overloaded.

  • Can have parameters.

  • Can have default arguments.

  • Cannot be declared static.

  • Is not inherited in the usual sense.


2. Basic Syntax of a Constructor

class ClassName
{
public:
    ClassName()
    {
        // initialization
    }
};

Example:

class Student
{
    int rollNo;

public:
    Student()
    {
        rollNo = 101;
    }
};

When:

Student s;

is executed, rollNo is initialized to 101.


3. Simple Example of Constructor

#include <iostream>
using namespace std;

class Student
{
    int rollNo;

public:

    Student()
    {
        rollNo = 101;
        cout << "Constructor called" << endl;
    }

    void display()
    {
        cout << "Roll No: " << rollNo << endl;
    }
};

int main()
{
    Student s;

    s.display();

    return 0;
}

Output

Constructor called
Roll No: 101

The statement:

Student s;

creates the object and automatically invokes:

Student()

4. Types of Constructors

The most important constructor types are:

                    Constructors
                         |
          +--------------+--------------+
          |              |              |
       Default      Parameterized      Copy
      Constructor    Constructor     Constructor

In practical C++, constructors can also involve default arguments, delegating constructors, move constructors, and other modern features. For the present OOP unit, default, parameterized, and copy constructors are the core types.



Image




5. Default Constructor

A constructor that can be called without providing arguments is called a default constructor.

Example:

class Student
{
public:

    Student()
    {
        cout << "Default constructor";
    }
};

Object creation:

Student s;

automatically calls the constructor.

Example

#include <iostream>
using namespace std;

class Student
{
    int rollNo;

public:

    Student()
    {
        rollNo = 100;
    }

    void display()
    {
        cout << "Roll No = " << rollNo << endl;
    }
};

int main()
{
    Student s;

    s.display();

    return 0;
}

Output

Roll No = 100

6. Important Point About Default Constructors

There is an important distinction between:

A user-provided default constructor

Student()
{
    rollNo = 100;
}

and a compiler-provided/defaulted constructor.

If the programmer does not declare any constructor, the compiler can implicitly declare a default constructor for the class in appropriate circumstances.

For example:

class Student
{
    int rollNo;
};

The class can be declared as:

Student s;

However, the integer member rollNo is not automatically initialized to zero merely because the constructor exists implicitly. For an automatic/local object, an uninitialized built-in data member can contain an indeterminate value.

Therefore, explicitly initializing data members is important.


7. Parameterized Constructor

A constructor that accepts one or more parameters is called a parameterized constructor.

Syntax

ClassName(data_type parameter1, data_type parameter2)
{
    // initialization
}

Example:

class Student
{
    int rollNo;
    float marks;

public:

    Student(int r, float m)
    {
        rollNo = r;
        marks = m;
    }
};

Object creation:

Student s(101, 85.5);

The values are passed to the constructor.


8. Example of Parameterized Constructor

#include <iostream>
using namespace std;

class Student
{
    int rollNo;
    float marks;

public:

    Student(int r, float m)
    {
        rollNo = r;
        marks = m;
    }

    void display()
    {
        cout << "Roll No: " << rollNo << endl;
        cout << "Marks: " << marks << endl;
    }
};

int main()
{
    Student s(101, 87.5);

    s.display();

    return 0;
}

Output

Roll No: 101
Marks: 87.5

Flow

Student s(101, 87.5)
          |
          ↓
 Student(int r, float m)
          |
     +----+----+
     |         |
    101       87.5
     |         |
     ↓         ↓
 rollNo      marks

9. Why Parameterized Constructors Are Useful

Suppose we want to create three student objects:

Student s1(101, 85);
Student s2(102, 91);
Student s3(103, 78);

Each object can be initialized with different values.

s1 → rollNo = 101, marks = 85
s2 → rollNo = 102, marks = 91
s3 → rollNo = 103, marks = 78

Thus, parameterized constructors provide a convenient way to initialize different objects with different values at the time of creation.


10. Constructor Using Initialization List

A parameterized constructor is often better written using a constructor initialization list.

class Student
{
    int rollNo;
    float marks;

public:

    Student(int r, float m) : rollNo(r), marks(m)
    {
    }
};

This directly initializes the data members.

For example:

Student s(101, 85.5);

The initialization list is particularly important for:

  • const data members

  • Reference data members

  • Members without default constructors

  • Efficient initialization of class-type members

Recommended Style

Student(int r, float m)
    : rollNo(r), marks(m)
{
}

rather than:

Student(int r, float m)
{
    rollNo = r;
    marks = m;
}

Both can work, but they are not technically identical: the initialization list performs initialization, while assignments in the constructor body perform assignment after the members have already been initialized.


11. Copy Constructor

A copy constructor is a constructor used to initialize a new object from an existing object of the same class.

General Syntax

ClassName(const ClassName &object)
{
    // copy data
}

Example:

class Student
{
    int rollNo;

public:

    Student(int r)
    {
        rollNo = r;
    }

    Student(const Student &s)
    {
        rollNo = s.rollNo;
    }
};

Here:

Student s1(101);
Student s2(s1);

creates s2 as a copy of s1.


12. Example of Copy Constructor

#include <iostream>
using namespace std;

class Student
{
    int rollNo;
    float marks;

public:

    Student(int r, float m)
    {
        rollNo = r;
        marks = m;
    }

    Student(const Student &s)
    {
        rollNo = s.rollNo;
        marks = s.marks;
    }

    void display()
    {
        cout << "Roll No: " << rollNo << endl;
        cout << "Marks: " << marks << endl;
    }
};

int main()
{
    Student s1(101, 88.5);

    Student s2(s1);

    cout << "First object:" << endl;
    s1.display();

    cout << "\nCopied object:" << endl;
    s2.display();

    return 0;
}

Output

First object:
Roll No: 101
Marks: 88.5

Copied object:
Roll No: 101
Marks: 88.5

Visual Representation

       Existing Object
          s1
    +-------------+
    | rollNo 101  |
    | marks  88.5 |
    +-------------+
           |
           | copy constructor
           ↓
       New Object
          s2
    +-------------+
    | rollNo 101  |
    | marks  88.5 |
    +-------------+

13. Why const Reference Is Used in a Copy Constructor

The standard form is:

Student(const Student &s)

There are two important parts.

&

The object is passed by reference, avoiding creation of another copy.

const

The source object should not be modified during copying.

Therefore:

const Student &s

is the conventional and appropriate form for a copy constructor.


14. When Is a Copy Constructor Called?

A copy constructor can be invoked in several situations.

1. Initialization from another object

Student s1(101);
Student s2(s1);

2. Copy initialization

Student s1(101);
Student s2 = s1;

3. Passing an object by value

void display(Student s)
{
}

Calling:

display(s1);

may require a copy of s1.

4. Returning an object by value

Student createStudent()
{
    Student s(101);
    return s;
}

Copy/move construction may be involved depending on the situation and compiler optimizations such as copy elision.


15. Compiler-Generated Copy Constructor

If we do not define a copy constructor, C++ can provide an implicitly declared copy constructor.

Example:

class Student
{
public:
    int rollNo;
};

Then:

Student s1;
s1.rollNo = 101;

Student s2 = s1;

The compiler-generated copy constructor performs member-wise copying.

Conceptually:

s1.rollNo
    |
    | copy
    ↓
s2.rollNo

For classes containing only ordinary value-type members, this is usually sufficient.


16. Shallow Copy

Consider a class containing a pointer:

class Student
{
public:
    int *marks;

    Student()
    {
        marks = new int(90);
    }
};

If the default copy constructor is used:

Student s1;
Student s2 = s1;

the pointer value is copied.

Conceptually:

s1.marks ─────┐
              ↓
          +-------+
          |  90   |
          +-------+
              ↑
              |
s2.marks ─────┘

Both objects point to the same dynamically allocated memory.

This is commonly called a shallow copy.

It can lead to serious problems when a class owns dynamically allocated resources.


17. Deep Copy

A deep copy creates separate dynamically allocated memory for the copied object and copies the actual data.

Example:

#include <iostream>
using namespace std;

class Student
{
    int *marks;

public:

    Student(int m)
    {
        marks = new int(m);
    }

    Student(const Student &s)
    {
        marks = new int(*s.marks);
    }

    void display()
    {
        cout << "Marks = " << *marks << endl;
    }

    ~Student()
    {
        delete marks;
    }
};

int main()
{
    Student s1(90);

    Student s2(s1);

    s2.display();

    return 0;
}

Here:

marks = new int(*s.marks);

creates a new memory location and copies the value.

             s1
             |
             ↓
          +-----+
          | 90  |
          +-----+

             s2
             |
             ↓
          +-----+
          | 90  |
          +-----+

The two objects own separate memory.

Image

Image

Image

Image

Image


18. Constructor Overloading

Since constructors can be overloaded, a class can have multiple constructors with different parameter lists.

Example:

class Student
{
public:

    Student()
    {
        cout << "Default constructor" << endl;
    }

    Student(int r)
    {
        cout << "Parameterized constructor" << endl;
    }

    Student(int r, float m)
    {
        cout << "Parameterized constructor with two arguments" << endl;
    }
};

Now:

Student s1;
Student s2(101);
Student s3(101, 85.5);

call different constructors.

This is an application of function overloading, because constructors are overloaded based on their parameter lists.


19. Constructor vs Normal Member Function

ConstructorNormal Member Function
Same name as classCan have any valid name
No return typeHas a return type or void
Automatically called during object initializationUsually called explicitly
Initializes objectPerforms an operation
Called when object is createdCan be called multiple times
Cannot be staticCan be static
Can be overloadedCan be overloaded

20. Constructor vs Destructor

A destructor is used for cleanup when an object reaches the end of its lifetime.

ConstructorDestructor
Initializes objectPerforms cleanup
Same name as class~ClassName()
Called when object is createdCalled when object is destroyed
Can be overloadedCannot be overloaded
Can accept parametersTakes no parameters
Multiple constructors possibleOnly one destructor per class

Example:

class Student
{
public:

    Student()
    {
        cout << "Constructor" << endl;
    }

    ~Student()
    {
        cout << "Destructor" << endl;
    }
};

21. Constructor with Default Arguments

A constructor can also use default arguments.

class Student
{
    int rollNo;
    int marks;

public:

    Student(int r = 0, int m = 0)
    {
        rollNo = r;
        marks = m;
    }
};

Now:

Student s1;
Student s2(101);
Student s3(101, 85);

are all possible.

The compiler supplies default values for missing arguments.

However, when designing a class, default arguments should be used carefully because they can interact with overloaded constructors and create ambiguity.


22. Constructor Initialization of const and Reference Members

A constructor initialization list becomes necessary for certain members.

Example:

class Test
{
    const int x;
    int &ref;

public:

    Test(int a, int b)
        : x(a), ref(b)
    {
    }
};

Here x and ref must be initialized through the initialization list.

This is an important reason why constructor initialization lists should be understood properly.


23. Constructors and Dynamic Objects

Constructors are automatically called even when objects are dynamically allocated.

class Student
{
public:

    Student()
    {
        cout << "Constructor called" << endl;
    }

    ~Student()
    {
        cout << "Destructor called" << endl;
    }
};

Now:

Student *ptr = new Student;

calls the constructor.

When:

delete ptr;

is executed, the destructor is called.

new Student
     ↓
Constructor
     ↓
Object created
     ↓
delete ptr
     ↓
Destructor

24. Important Examination Points

Constructor

A constructor is a special member function that is automatically called when an object is created and is primarily used to initialize the object.

Default Constructor

A constructor that can be invoked without arguments is called a default constructor.

Parameterized Constructor

A constructor that accepts one or more parameters to initialize an object with specified values is called a parameterized constructor.

Copy Constructor

A copy constructor initializes a new object using an existing object of the same class.

Standard form:

ClassName(const ClassName &obj);

Deep Copy

Deep copying creates an independent copy of dynamically allocated resources instead of merely copying their addresses.


25. Quick Revision

                    CONSTRUCTOR
                         |
          +--------------+--------------+
          |              |              |
       DEFAULT      PARAMETERIZED      COPY
          |              |              |
     Student()      Student(int)   Student(const Student&)
          |              |              |
     No argument     Initial values    Existing object

Example

class Student
{
    int rollNo;

public:

    // Default constructor
    Student()
    {
        rollNo = 0;
    }

    // Parameterized constructor
    Student(int r)
    {
        rollNo = r;
    }

    // Copy constructor
    Student(const Student &s)
    {
        rollNo = s.rollNo;
    }
};

Object creation:

Student s1;          // Default constructor

Student s2(101);     // Parameterized constructor

Student s3(s2);      // Copy constructor

One important memory rule

Constructor → Object initialization

Destructor  → Object cleanup

Copy Constructor → Initialization of a new object
                   from an existing object

And remember:

Constructor = same class name + no return type + automatic invocation during object initialization.

September 14, 2026

Function Overloading in C++


Function Overloading in C++

Function overloading is an important feature of compile-time polymorphism in C++. It allows multiple functions to have the same name but different parameter lists. The compiler determines which function should be called based on the number, type, or order of the arguments supplied during the function call.

Function overloading improves readability, reusability, and organization of a program because related operations can be represented using a common function name.

Image

Image

Image

Image

Image


1. Need for Function Overloading

Consider a program that calculates the sum of different types of values.

Without function overloading, we might use different names:

int addInt(int a, int b);
float addFloat(float a, float b);
double addDouble(double a, double b);

The operations are conceptually the same, but three different names are required.

Using function overloading, we can write:

int add(int a, int b);
float add(float a, float b);
double add(double a, double b);

Now the same name add() represents the same logical operation for different parameter types.


2. Definition of Function Overloading

Function overloading is the mechanism of defining two or more functions with the same name but different parameter lists in the same scope.

The parameter list may differ in:

  1. Number of parameters

  2. Type of parameters

  3. Order of parameters

For example:

void display(int);
void display(float);
void display(int, int);

All three functions have the same name:

display()

but different parameter lists.


3. General Syntax

return_type function_name(parameter_list);

return_type function_name(different_parameter_list);

Example:

int sum(int a, int b);

float sum(float a, float b);

int sum(int a, int b, int c);

The compiler selects the appropriate function based on the arguments used in the function call.


4. How Function Overloading Works

Consider:

void show(int x)
{
    cout << "Integer";
}

void show(double x)
{
    cout << "Double";
}

Function calls:

show(10);

select:

show(int)

while:

show(10.5);

select:

show(double)

Conceptual Flow

                 show()
                   |
          +--------+--------+
          |        |        |
       show(int) show(double) show(int,int)
          ↑        ↑          ↑
         10       10.5       10,20

The decision is made by the compiler, so function overloading is a form of compile-time polymorphism.


5. Example: Function Overloading Based on Number of Arguments

#include <iostream>
using namespace std;

class Calculator
{
public:

    int add(int a, int b)
    {
        return a + b;
    }

    int add(int a, int b, int c)
    {
        return a + b + c;
    }
};

int main()
{
    Calculator obj;

    cout << "Sum of two numbers = "
         << obj.add(10, 20) << endl;

    cout << "Sum of three numbers = "
         << obj.add(10, 20, 30) << endl;

    return 0;
}

Output

Sum of two numbers = 30
Sum of three numbers = 60

Here both functions are named:

add()

but one accepts two arguments and the other accepts three arguments.


6. Function Overloading Based on Data Type

Functions can also be overloaded by changing the type of parameters.

#include <iostream>
using namespace std;

class Display
{
public:

    void show(int x)
    {
        cout << "Integer: " << x << endl;
    }

    void show(double x)
    {
        cout << "Double: " << x << endl;
    }

    void show(char x)
    {
        cout << "Character: " << x << endl;
    }
};

int main()
{
    Display obj;

    obj.show(10);
    obj.show(25.5);
    obj.show('A');

    return 0;
}

Output

Integer: 10
Double: 25.5
Character: A

The compiler determines the appropriate version according to the argument type.


7. Function Overloading Based on Order of Parameters

The functions may also differ in the order of parameter types.

void display(int, float);
void display(float, int);

These are valid overloaded functions because their parameter lists are different.

Example:

#include <iostream>
using namespace std;

void display(int a, float b)
{
    cout << "Integer followed by Float" << endl;
}

void display(float a, int b)
{
    cout << "Float followed by Integer" << endl;
}

int main()
{
    display(10, 20.5f);
    display(10.5f, 20);

    return 0;
}

Output

Integer followed by Float
Float followed by Integer

8. Function Signature

The compiler distinguishes overloaded functions primarily through their parameter-type list.

For example:

void show(int);
void show(double);
void show(int, int);

The relevant distinctions are:

show(int)
show(double)
show(int, int)

The return type alone is not sufficient to overload a function.


9. Return Type Alone Cannot Overload a Function

The following is invalid:

int calculate(int a)
{
    return a;
}

double calculate(int a)
{
    return a;
}

Both functions have the same parameter list:

calculate(int)

The only difference is the return type.

C++ does not allow this as function overloading.

Incorrect

int fun(int);
double fun(int);

Correct

int fun(int);
double fun(double);

or:

int fun(int);
int fun(int, int);

10. Function Overloading and Default Arguments

Default arguments can sometimes create ambiguity with overloaded functions.

Consider:

void show(int a)
{
    cout << "One parameter";
}

void show(int a, int b = 10)
{
    cout << "Two parameters";
}

Now:

show(5);

can match both:

show(int)

and:

show(int, int)

because b has a default value.

Therefore, the call becomes ambiguous and should be avoided.

Important Point

When using function overloading and default arguments together, ensure that every function call has a clear and unique match.


11. Function Overloading and Type Conversion

Sometimes the compiler performs implicit type conversion to find a suitable overloaded function.

Example:

void show(int x)
{
    cout << "Integer";
}

void show(double x)
{
    cout << "Double";
}

If we write:

show(10);

the int version is an exact match.

If we write:

show(10.5);

the double version is an exact match.

The compiler generally prefers the best available match rather than arbitrarily selecting a function.


12. Ambiguity in Function Overloading

An ambiguity occurs when the compiler cannot determine a unique best overloaded function.

Example:

void show(int x)
{
    cout << "Integer";
}

void show(double x)
{
    cout << "Double";
}

Now consider:

show(10.5f);

A float argument can potentially be converted to either int or double. Depending on the complete overload set and conversion ranking, the compiler may be unable to choose a unique best match.

Therefore, overloaded functions should be designed carefully to avoid competing implicit conversions.


13. Function Overloading with Different Number and Types of Parameters

A class can contain several overloaded functions.

class Calculator
{
public:

    int calculate(int a, int b)
    {
        return a + b;
    }

    float calculate(float a, float b)
    {
        return a + b;
    }

    int calculate(int a, int b, int c)
    {
        return a + b + c;
    }
};

Here:

calculate(int, int)
calculate(float, float)
calculate(int, int, int)

are different overloaded functions.


14. Function Overloading in a Class

Function overloading is frequently used with member functions.

#include <iostream>
using namespace std;

class Area
{
public:

    int calculate(int side)
    {
        return side * side;
    }

    int calculate(int length, int breadth)
    {
        return length * breadth;
    }
};

int main()
{
    Area obj;

    cout << "Square Area = "
         << obj.calculate(5) << endl;

    cout << "Rectangle Area = "
         << obj.calculate(5, 10) << endl;

    return 0;
}

Output

Square Area = 25
Rectangle Area = 50

The same function name calculate() is used for different calculations.


15. Function Overloading and Compile-Time Polymorphism

Function overloading is an example of static or compile-time polymorphism.

                  Polymorphism
                       |
             +---------+---------+
             |                   |
       Compile-time          Run-time
             |                   |
     Function Overloading   Virtual Functions
     Operator Overloading

Image

Image

Image

Image

Image

In function overloading, the compiler determines which function to call before the program executes.

For example:

obj.display(10);

The compiler resolves the call to the appropriate display() function based on the arguments.


16. Function Overloading vs Function Overriding

These two concepts are frequently confused.

Function OverloadingFunction Overriding
Same class/scope commonly usedRequires inheritance
Same function nameSame function name
Different parameter listGenerally same parameter list
Compile-time polymorphismRuntime polymorphism when virtual dispatch is involved
Inheritance not requiredInheritance required
Compiler selects overloadRuntime dispatch may select override

Example of Overloading

void show(int);
void show(double);

Example of Overriding

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

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

17. Advantages of Function Overloading

Function overloading provides several advantages:

1. Improved readability

Related operations can use the same meaningful name.

2. Code reusability

The same logical operation can be implemented for different parameter types.

3. Compile-time polymorphism

It provides an important form of static polymorphism.

4. Easier maintenance

Programmers can work with a common function name instead of remembering many different function names.

5. Natural interface design

For example:

print(int);
print(float);
print(string);

is more intuitive than:

printInteger(int);
printFloat(float);
printString(string);

18. Limitations and Important Considerations

Function overloading should not be used excessively.

If overloaded functions have very similar signatures and implicit conversions can make calls unclear, the program may produce compiler errors due to ambiguity.

For example, avoid creating many overloads such as:

void test(int);
void test(long);
void test(float);
void test(double);

unless there is a clear reason for each version.

Good overloading should make an interface simpler, not more confusing.


19. Complete Example

#include <iostream>
using namespace std;

class Calculator
{
public:

    int add(int a, int b)
    {
        return a + b;
    }

    double add(double a, double b)
    {
        return a + b;
    }

    int add(int a, int b, int c)
    {
        return a + b + c;
    }
};

int main()
{
    Calculator c;

    cout << "Integer addition: "
         << c.add(10, 20) << endl;

    cout << "Double addition: "
         << c.add(10.5, 20.5) << endl;

    cout << "Three-number addition: "
         << c.add(10, 20, 30) << endl;

    return 0;
}

Output

Integer addition: 30
Double addition: 31
Three-number addition: 60

Working

                 c.add()
                    |
       +------------+------------+
       |            |            |
    add(int,int) add(double,double) add(int,int,int)
       |            |            |
     10,20       10.5,20.5      10,20,30
       |            |            |
      30           31            60

20. Important Rules of Function Overloading

Remember these rules:

Same function name
        +
Different parameter list
        =
Function Overloading

The parameter list can differ by:

1. Number of parameters
2. Data type of parameters
3. Order of parameter types

But:

Different return type only
        ≠
Function Overloading

For example:

void fun(int);
void fun(double);          // Valid
void fun(int);
void fun(int, int);        // Valid
void fun(int, double);
void fun(double, int);     // Valid

But:

int fun(int);
double fun(int);           // Invalid

Quick Revision

                 FUNCTION OVERLOADING
                         |
             Same function name
                         |
             Different parameters
                         |
              Compiler resolves call
                         |
             Compile-time polymorphism

One-line definition for examination

Function overloading is a C++ feature in which two or more functions have the same name but different parameter lists, allowing the compiler to select the appropriate function at compile time.

Remember

Overloading → Same name, different parameters

Overriding → Inheritance + redefined virtual function

Return type alone → Cannot overload a function

September 14, 2026

Dynamic Allocation and Operators in C++

Dynamic Allocation and Operators in C++

Dynamic memory allocation is an important feature of C++ that allows a program to allocate and release memory during runtime. Unlike ordinary variables whose memory is generally determined when the program enters a scope, dynamically allocated memory is obtained from the free store (commonly called the heap) when required.

C++ provides the operators new and delete for dynamic memory management.

Image

Image

Image

Image

Image

Image


1. Need for Dynamic Memory Allocation

Consider an array:

int marks[50];

The size is fixed at the time of declaration. If the program later requires 100 elements, the original array cannot be resized.

Dynamic allocation allows memory to be requested according to the requirement at runtime.

For example:

int n;

cout << "Enter number of elements: ";
cin >> n;

int *p = new int[n];

Here, the number of integers is decided during program execution.

Advantages

Dynamic allocation is useful when:

  • The required memory size is not known beforehand.

  • Memory needs to be allocated only when required.

  • Large objects or arrays need controlled lifetime.

  • Dynamic data structures such as linked lists, trees, and graphs are implemented.

  • Objects need to be created and destroyed explicitly during program execution.


2. new Operator

The new operator dynamically allocates memory and returns the address of the allocated memory.

Syntax

For a single variable:

pointer = new data_type;

Example:

int *p = new int;

Memory for one int is allocated, and its address is stored in p.

We can assign a value using:

*p = 25;

or initialize it directly:

int *p = new int(25);

3. Dynamic Allocation of a Single Variable

#include <iostream>
using namespace std;

int main()
{
    int *p = new int;

    *p = 50;

    cout << "Value = " << *p << endl;

    delete p;

    return 0;
}

Output

Value = 50

Working

          Pointer p
             |
             | address
             ↓
       +-----------+
Heap → |    50     |
       +-----------+

The statement:

int *p = new int;

allocates memory dynamically.

The statement:

delete p;

releases that memory.


4. delete Operator

The delete operator releases memory that was allocated using new.

Syntax

delete pointer;

Example:

int *p = new int(100);

cout << *p;

delete p;

After:

delete p;

the dynamically allocated object no longer exists.

It is good practice to avoid subsequently using the pointer to access the released object. A pointer can be set to nullptr after deletion:

delete p;
p = nullptr;

5. Dynamic Allocation of Arrays

C++ provides new[] for dynamically allocating an array.

Syntax

pointer = new data_type[size];

Example:

int *arr = new int[5];

This creates an array of five integers dynamically.

The elements can be accessed using:

arr[0]
arr[1]
arr[2]

or pointer notation:

*(arr + 0)
*(arr + 1)
*(arr + 2)

6. Example of Dynamic Array

#include <iostream>
using namespace std;

int main()
{
    int n;

    cout << "Enter number of elements: ";
    cin >> n;

    int *arr = new int[n];

    for(int i = 0; i < n; i++)
    {
        arr[i] = (i + 1) * 10;
    }

    cout << "Array elements: ";

    for(int i = 0; i < n; i++)
    {
        cout << arr[i] << " ";
    }

    delete[] arr;

    arr = nullptr;

    return 0;
}

For input:

5

Output

Array elements: 10 20 30 40 50

Memory Concept

int *arr
   |
   ↓
+----+----+----+----+----+
| 10 | 20 | 30 | 40 | 50 |
+----+----+----+----+----+
  0    1    2    3    4

Image

Image

Image

Image

Image


7. delete[] Operator

When an array is allocated using:

new[]

it must be released using:

delete[]

Example:

int *arr = new int[10];

delete[] arr;
arr = nullptr;

Important Rule

new       → delete
new[]     → delete[]

Do not use:

delete arr;

for memory allocated as:

new int[10];

The correct form is:

delete[] arr;

8. Dynamic Allocation of Objects

The new operator can also dynamically create an object.

Suppose:

class Student
{
public:
    int rollNo;

    void display()
    {
        cout << "Roll No: " << rollNo << endl;
    }
};

An object can be dynamically created using:

Student *ptr = new Student;

The member can be accessed using the arrow operator:

ptr->rollNo = 101;
ptr->display();

Image

Image

Image

Image

Image


9. Example: Dynamic Object

#include <iostream>
using namespace std;

class Student
{
public:
    int rollNo;

    void display()
    {
        cout << "Roll No: " << rollNo << endl;
    }
};

int main()
{
    Student *ptr = new Student;

    ptr->rollNo = 101;

    ptr->display();

    delete ptr;
    ptr = nullptr;

    return 0;
}

Output

Roll No: 101

Here:

Student *ptr = new Student;

creates a Student object dynamically.

The pointer ptr stores its address.


10. Dynamic Allocation with Constructor

When an object is created using new, its constructor is automatically called.

#include <iostream>
using namespace std;

class Student
{
public:
    Student()
    {
        cout << "Constructor called" << endl;
    }

    ~Student()
    {
        cout << "Destructor called" << endl;
    }
};

int main()
{
    Student *s = new Student;

    delete s;

    return 0;
}

Output

Constructor called
Destructor called

Thus:

new object
    ↓
Constructor called
    ↓
Object exists
    ↓
delete object
    ↓
Destructor called

11. Dynamic Array of Objects

An array of objects can also be dynamically allocated.

Syntax

ClassName *ptr = new ClassName[size];

Example:

Student *students = new Student[5];

This creates five Student objects dynamically.

Each object can be accessed using:

students[0]
students[1]
students[2]

or:

(students + 0)->display();

12. Dynamic Allocation with Initialization

C++ allows dynamically allocated objects to be initialized.

For a fundamental type:

int *p = new int(100);

For an object:

Student *s = new Student();

For an array:

int *arr = new int[5]{10, 20, 30, 40, 50};

Example:

#include <iostream>
using namespace std;

int main()
{
    int *arr = new int[5]{10, 20, 30, 40, 50};

    for(int i = 0; i < 5; i++)
        cout << arr[i] << " ";

    delete[] arr;

    return 0;
}

Output

10 20 30 40 50

13. What Happens When Memory Allocation Fails?

Normally:

int *p = new int;

successfully allocates memory.

If a normal new expression cannot allocate the requested memory, it throws a std::bad_alloc exception.

Example:

try
{
    int *p = new int[1000000000000];
}
catch (const bad_alloc &e)
{
    cout << "Memory allocation failed";
}

For modern C++, this is generally preferable to assuming new simply returns NULL.

There is also a nothrow version:

int *p = new(nothrow) int[1000000];

if(p == nullptr)
{
    cout << "Memory allocation failed";
}

The nothrow form returns nullptr instead of throwing std::bad_alloc.


14. Dynamic Allocation and Memory Leak

A memory leak occurs when dynamically allocated memory is no longer accessible but has not been released.

Example:

int *p = new int(50);

p = nullptr;

The allocated memory is still present, but its address has been lost.

Therefore, it cannot be released using delete.

       p
       |
       ↓
    nullptr

Heap:
+-------+
|  50   |  ← inaccessible memory
+-------+

This is a memory leak.

Correct approach:

int *p = new int(50);

delete p;
p = nullptr;

15. Dangling Pointer

A dangling pointer is a pointer that still contains the address of an object whose lifetime has ended.

Example:

int *p = new int(50);

delete p;

Now p should not be dereferenced.

Better:

delete p;
p = nullptr;

Then:

if(p != nullptr)
{
    cout << *p;
}

This prevents accidental access through the pointer.


16. new and delete with Classes

Dynamic allocation is particularly important in object-oriented programming because objects can have constructors and destructors.

class Employee
{
    int id;

public:

    Employee(int x)
    {
        id = x;
    }

    void display()
    {
        cout << "ID = " << id << endl;
    }
};

Dynamic object:

Employee *e = new Employee(101);

e->display();

delete e;

The sequence is:

new Employee(101)
        ↓
Constructor executes
        ↓
Object created
        ↓
e->display()
        ↓
delete e
        ↓
Destructor executes
        ↓
Memory released

17. Dynamic Allocation Operators and Ordinary Operators

The term operator in C++ refers to symbols that perform operations on operands. Dynamic memory management uses special operators:

OperatorPurpose
newDynamically allocates one object
deleteReleases one dynamically allocated object
new[]Dynamically allocates an array
delete[]Releases a dynamically allocated array

Example:

int *p = new int;
delete p;

and:

int *arr = new int[10];
delete[] arr;

18. new/delete vs malloc/free

C++ programs may encounter the C functions malloc() and free(), but they should not be confused with C++ new and delete.

Featurenew/deletemalloc/free
LanguageC++C
Allocationnewmalloc()
Deallocationdeletefree()
Constructor calledYes, for objectsNo
Destructor calledYes, for objectsNo
Type returnedProperly typed pointervoid* in C
Array allocationnew[]malloc()
C++ object managementPreferredGenerally not preferred

Never Mix Them

Incorrect:

int *p = new int;

free(p);        // Wrong

Correct:

int *p = new int;

delete p;

Similarly:

int *p = (int*)malloc(sizeof(int));

delete p;       // Wrong

Use:

free(p);

when memory was allocated with malloc().


19. Modern C++ Recommendation

Although new and delete are fundamental concepts and are important for understanding C++ memory management, modern C++ generally recommends RAII and smart pointers for managing dynamically allocated resources.

For example:

#include <memory>

unique_ptr<int> p = make_unique<int>(100);

The memory is automatically released when p goes out of scope.

Similarly:

auto student = make_unique<Student>();

is preferred in many modern applications over manually writing:

Student *student = new Student;

delete student;

However, understanding new, delete, new[], and delete[] remains essential for understanding pointers, object lifetime, constructors/destructors, and legacy C++ code.


20. Common Errors

Error 1: Forgetting delete

int *p = new int(10);

// delete missing

This can cause a memory leak.


Error 2: Wrong delete operator

int *arr = new int[10];

delete arr;       // Incorrect

Correct:

delete[] arr;

Error 3: Accessing after deletion

int *p = new int(10);

delete p;

cout << *p;       // Undefined behavior

Error 4: Losing the allocated address

int *p = new int(10);

p = nullptr;

The allocated memory is leaked.


Error 5: Mixing allocation and deallocation mechanisms

int *p = new int;

free(p);          // Incorrect

Use matching mechanisms.


21. Complete Example

#include <iostream>
using namespace std;

class Student
{
public:
    int rollNo;

    Student()
    {
        rollNo = 0;
    }

    void display()
    {
        cout << "Roll No: " << rollNo << endl;
    }
};

int main()
{
    // Dynamic object
    Student *s = new Student;

    s->rollNo = 101;
    s->display();

    // Dynamic array of objects
    Student *students = new Student[3];

    students[0].rollNo = 101;
    students[1].rollNo = 102;
    students[2].rollNo = 103;

    cout << "\nStudent records:\n";

    for(int i = 0; i < 3; i++)
    {
        students[i].display();
    }

    // Release memory
    delete s;
    s = nullptr;

    delete[] students;
    students = nullptr;

    return 0;
}

Output

Roll No: 101

Student records:
Roll No: 101
Roll No: 102
Roll No: 103

22. Summary

Dynamic allocation allows C++ programs to obtain memory at runtime according to program requirements. The new operator allocates memory and returns an appropriate pointer, while delete releases a single dynamically allocated object. For arrays, C++ provides new[] and delete[].

The concept becomes especially important in object-oriented programming because dynamically created objects are initialized through constructors and destroyed through destructors. Proper memory management is essential to avoid memory leaks, dangling pointers, and undefined behavior.

Quick Revision

              Dynamic Memory
                    |
          +---------+---------+
          |                   |
       Single               Array
          |                   |
        new                 new[]
          |                   |
       delete              delete[]
          |
     Dynamic Object
          |
      Constructor
          ↓
       Object
          ↓
       delete
          ↓
      Destructor

Most important rule to remember:

new       → delete
new[]     → delete[]

And for modern C++:

Prefer RAII / smart pointers
when manual ownership is not specifically required.
September 14, 2026

Dynamic Allocation Operator: Pointers to Derived Types, Pointers to Class Members, and References in C++


Dynamic Allocation Operator:
Pointers to Derived Types, Pointers to Class Members, and References in C++

These concepts are important in C++ because they extend the use of pointers beyond ordinary variables and objects. Pointers to derived types are mainly used with inheritance and polymorphism, pointers to class members provide a way to refer to data members or member functions of a class, and references provide an alternative name (alias) for an existing variable or object.


1. Pointers to Derived Types

In C++, a pointer can point to an object of a derived class. More importantly, a base-class pointer can also point to an object of a derived class.

This is one of the fundamental mechanisms used to achieve runtime polymorphism.

Basic Concept

Suppose we have a base class Animal and a derived class Dog.

class Animal
{
public:
    void eat()
    {
        cout << "Animal eats" << endl;
    }
};

class Dog : public Animal
{
public:
    void bark()
    {
        cout << "Dog barks" << endl;
    }
};

We can create a pointer to the derived class:

Dog d;
Dog *ptr = &d;

Here:

  • d is an object of class Dog.

  • ptr is a pointer to Dog.

  • ptr stores the address of d.

We can access members using the arrow operator:

ptr->bark();
ptr->eat();

Visual Representation

Image

Image

Image

Image

Conceptually:

        Derived Object
     +------------------+
     |      Dog d       |
     |------------------|
     | Animal members   |
     | Dog members      |
     +------------------+
             ↑
             |
          Dog *ptr

2. Base-Class Pointer Pointing to Derived Object

A particularly important feature is:

Animal *ptr;
Dog d;

ptr = &d;

Although ptr is declared as Animal*, it can store the address of a Dog object because Dog is derived from Animal.

Animal
   ↑
   |
  Dog

Animal *ptr
     |
     ↓
+-------------+
| Dog object  |
+-------------+

This is called upcasting.

Example

#include <iostream>
using namespace std;

class Animal
{
public:
    void eat()
    {
        cout << "Animal eats" << endl;
    }
};

class Dog : public Animal
{
public:
    void bark()
    {
        cout << "Dog barks" << endl;
    }
};

int main()
{
    Dog d;

    Animal *ptr = &d;

    ptr->eat();

    return 0;
}

Output

Animal eats

Notice that:

ptr->eat();

is valid because eat() belongs to the base class.

However:

ptr->bark();

is not valid, because the static type of ptr is Animal*, and bark() is not a member of Animal.

Important Rule

Base *ptr = &DerivedObject;

is allowed for public inheritance.

But:

Derived *ptr = &BaseObject;

is not automatically allowed.


3. Pointers and Runtime Polymorphism

Pointers to derived types become especially useful when virtual functions are used.

Consider:

#include <iostream>
using namespace std;

class Animal
{
public:
    virtual void sound()
    {
        cout << "Animal sound" << endl;
    }
};

class Dog : public Animal
{
public:
    void sound() override
    {
        cout << "Dog barks" << endl;
    }
};

int main()
{
    Dog d;

    Animal *ptr = &d;

    ptr->sound();

    return 0;
}

Output

Dog barks

Here:

Animal *ptr = &d;

The pointer is of type Animal*, but it points to a Dog object.

Because sound() is declared virtual, C++ performs dynamic binding and calls:

Dog::sound()

rather than:

Animal::sound()

Conceptual Flow

             Animal
               |
        virtual sound()
               ↑
               |
              Dog
               |
        overridden sound()
               ↑
               |
          Animal *ptr
               |
               ↓
          Dog object
               |
               ↓
       Dog::sound() called

Image

Image

Image

Image


4. Pointer to a Derived Class Directly

A derived-class pointer can access both inherited and derived-class members.

#include <iostream>
using namespace std;

class Person
{
public:
    void displayPerson()
    {
        cout << "Person information" << endl;
    }
};

class Student : public Person
{
public:
    void displayStudent()
    {
        cout << "Student information" << endl;
    }
};

int main()
{
    Student s;
    Student *ptr = &s;

    ptr->displayPerson();
    ptr->displayStudent();

    return 0;
}

Output

Person information
Student information

Because ptr has type Student*, it can access members available through Student, including inherited public members.


5. Pointers to Class Members

A pointer to a class member is different from an ordinary pointer.

An ordinary pointer stores the address of an object or variable:

int *p;

A pointer to a class member identifies a member belonging to a particular class:

int MyClass::*ptr;

There are two important forms:

  1. Pointer to a data member

  2. Pointer to a member function

Image

Image


6. Pointer to a Data Member

Consider:

class Student
{
public:
    int rollNo;
    float marks;
};

A pointer to the rollNo member can be declared as:

int Student::*ptr;

The ::* operator is used to declare a pointer to a class data member.

Assigning a Member

ptr = &Student::rollNo;

The complete example is:

#include <iostream>
using namespace std;

class Student
{
public:
    int rollNo;
    float marks;
};

int main()
{
    Student s;

    s.rollNo = 101;
    s.marks = 85.5;

    int Student::*ptr;

    ptr = &Student::rollNo;

    cout << s.*ptr << endl;

    return 0;
}

Output

101

The important expression is:

s.*ptr

It means:

Access the member identified by ptr from object s.


7. Operators Used with Pointers to Class Members

There are two important operators.

.* Operator

Used when we have an object.

object.*pointer

Example:

s.*ptr

->* Operator

Used when we have a pointer to an object.

objectPointer->*memberPointer

Example:

Student *p = &s;

cout << p->*ptr;

Comparison

SituationOperatorExample
Object + member pointer.*s.*ptr
Object pointer + member pointer->*p->*ptr

8. Complete Example of Data-Member Pointer

#include <iostream>
using namespace std;

class Student
{
public:
    int rollNo;
    float marks;
};

int main()
{
    Student s;

    s.rollNo = 101;
    s.marks = 89.5;

    int Student::*pRoll;
    float Student::*pMarks;

    pRoll = &Student::rollNo;
    pMarks = &Student::marks;

    cout << "Roll No: " << s.*pRoll << endl;
    cout << "Marks: " << s.*pMarks << endl;

    Student *ptr = &s;

    cout << "Using object pointer:" << endl;
    cout << "Roll No: " << ptr->*pRoll << endl;
    cout << "Marks: " << ptr->*pMarks << endl;

    return 0;
}

Output

Roll No: 101
Marks: 89.5
Using object pointer:
Roll No: 101
Marks: 89.5

9. Pointer to a Member Function

C++ also allows a pointer to refer to a member function.

Consider:

class Student
{
public:
    void display()
    {
        cout << "Student details";
    }
};

A pointer to this member function can be declared as:

void (Student::*ptr)();

The member function is assigned using:

ptr = &Student::display;

The function can then be called using an object:

(s.*ptr)();

or an object pointer:

(ptrObject->*ptr)();

Example

#include <iostream>
using namespace std;

class Student
{
public:
    void display()
    {
        cout << "Student display function" << endl;
    }
};

int main()
{
    Student s;

    void (Student::*ptr)();

    ptr = &Student::display;

    (s.*ptr)();

    return 0;
}

Output

Student display function

10. References in C++

A reference is an alternative name or alias for an existing variable.

It does not create a separate object.

Syntax

data_type &reference_name = variable;

Example:

int x = 10;

int &ref = x;

Here:

x
+------+
|  10  |
+------+
   ↑
   |
  ref

Both x and ref refer to the same integer object.

Image

Image

Image

Image

Image


11. Example of Reference

#include <iostream>
using namespace std;

int main()
{
    int x = 10;

    int &ref = x;

    cout << "x = " << x << endl;
    cout << "ref = " << ref << endl;

    ref = 25;

    cout << "After modification:" << endl;
    cout << "x = " << x << endl;
    cout << "ref = " << ref << endl;

    return 0;
}

Output

x = 10
ref = 10
After modification:
x = 25
ref = 25

When we write:

ref = 25;

the original variable x is modified.


12. Reference as a Function Parameter

One of the most common uses of references is passing arguments by reference.

Without Reference

void change(int x)
{
    x = 50;
}

The function receives a copy, so the original variable is not changed.

With Reference

void change(int &x)
{
    x = 50;
}

Now x refers to the original variable.

Example

#include <iostream>
using namespace std;

void change(int &x)
{
    x = 50;
}

int main()
{
    int a = 10;

    cout << "Before: " << a << endl;

    change(a);

    cout << "After: " << a << endl;

    return 0;
}

Output

Before: 10
After: 50

13. Reference and Function Return

A function can also return a reference.

int& getValue(int &x)
{
    return x;
}

Example:

#include <iostream>
using namespace std;

int& getValue(int &x)
{
    return x;
}

int main()
{
    int a = 10;

    getValue(a) = 100;

    cout << a << endl;

    return 0;
}

Output

100

Here, getValue(a) refers to a, so assigning 100 changes the original variable.

Important: A function should not return a reference to a local variable because that local object is destroyed when the function ends.

Incorrect:

int& test()
{
    int x = 10;
    return x;       // Wrong
}

14. References to Objects

References can also refer to objects.

class Student
{
public:
    int rollNo;
};

int main()
{
    Student s;

    Student &ref = s;

    ref.rollNo = 101;

    cout << s.rollNo;
}

Output

101

Here:

       Student Object
       +-------------+
       | rollNo =101 |
       +-------------+
          ↑       ↑
          |       |
          s      ref

Both s and ref refer to the same object.


15. Reference vs Pointer

Pointers and references both allow indirect access to objects, but they are not the same.

FeaturePointerReference
Declarationint *pint &r
Can be nullYesNormally no valid null reference
Can be reassignedYesNo, after initialization
Requires initializationNot necessarilyYes
Access value*pDirectly use r
Address operation&xReference itself is an alias
Supports pointer arithmeticYesNo
Can point to different objectsYesNo
Common useDynamic memory, arrays, polymorphismFunction parameters, aliases

Example

Pointer:

int a = 10;
int b = 20;

int *p = &a;

p = &b;

The pointer can be changed to point to b.

Reference:

int a = 10;
int b = 20;

int &r = a;

r remains an alias for a; it cannot later be made an alias for b.


16. Pointer to Derived Type vs Reference to Derived Type

Both pointers and references can be used with inheritance.

Pointer

Dog d;

Animal *p = &d;

Reference

Dog d;

Animal &r = d;

Both can refer to the Dog object through its Animal interface.

With a virtual function:

class Animal
{
public:
    virtual void sound()
    {
        cout << "Animal sound";
    }
};

class Dog : public Animal
{
public:
    void sound() override
    {
        cout << "Dog barks";
    }
};

Both:

Animal *p = &d;
p->sound();

and:

Animal &r = d;
r.sound();

will invoke:

Dog::sound()

because of runtime polymorphism.


17. Important Syntax Summary

Pointer to Object

Student s;
Student *p = &s;

p->display();

Pointer to Derived Object

Dog d;
Animal *p = &d;

Pointer to Data Member

int Student::*p;
p = &Student::rollNo;

cout << s.*p;

Pointer to Member Function

void (Student::*p)();
p = &Student::display;

(s.*p)();

Reference

int x = 10;
int &r = x;

Reference Parameter

void display(int &x)
{
    // x refers to original argument
}

18. Key Points for Examination

  1. A derived-class pointer can directly point to a derived-class object.

  2. A base-class pointer can point to a derived-class object through public inheritance.

  3. Base-class pointers are extensively used for runtime polymorphism.

  4. A virtual function enables the appropriate overridden function to be selected at runtime.

  5. A pointer to a class data member is declared using the ::* syntax.

  6. .* is used with an object and a pointer-to-member.

  7. ->* is used with an object pointer and a pointer-to-member.

  8. A pointer to a member function requires the complete member-function pointer type.

  9. A reference is an alias for an existing object or variable.

  10. A reference must normally be initialized when declared.

  11. A reference cannot be reseated to refer to another object.

  12. References are particularly useful for pass-by-reference and avoiding unnecessary copying.

  13. A function should not return a reference to a local variable.

  14. Pointers and references are important tools for implementing polymorphism, efficient parameter passing, and object manipulation.

Quick Revision

Pointers to Derived Types
        ↓
Inheritance + Polymorphism
        ↓
Base pointer → Derived object

Pointers to Class Members
        ↓
Data member → int Class::*
Function member → return_type (Class::*)()

References
        ↓
Alias of existing object
        ↓
int &r = x
        ↓
Useful for pass-by-reference