OOP Unit 2 Notes

Download as pdf or txt
Download as pdf or txt
You are on page 1of 53

1|Page

Unit – II
Inheritance and Pointers
1. Inheritance

Inheritance is one of the core concepts of Object-Oriented Programming (OOP) in C++. It


allows a new class (called a derived class or child class) to inherit the properties and behaviors
(data members and member functions) of an existing class (called a base class or parent class).
This helps in code reuse and establishing a relationship between different classes.

1.1 Base Class and Derived Class

In C++, base class and derived class are key components of inheritance, a fundamental
concept of Object-Oriented Programming (OOP). They establish a relationship between two or
more classes where one class (derived class) inherits properties and behaviors from another
class (base class).

Base Class (Parent Class):

 The base class is the class whose members (attributes and methods) are inherited by
another class.

 It contains common functionality that can be shared with one or more derived classes.

 The base class serves as a blueprint for derived classes.

Derived Class (Child Class):

 The derived class is the class that inherits members from the base class.

 It can extend or modify the functionality inherited from the base class by adding new
members or overriding base class methods.

 The derived class can access the members of the base class based on the access
specifiers (public, protected, or private).

Syntax:

class BaseClass {
// Members of the base class
2|Page

};

class DerivedClass : public BaseClass {


// Members of the derived class
};
Here, DerivedClass inherits from BaseClass. The public keyword indicates that the public
members of the base class will remain public in the derived class.

Example: Base and Derived Class in C++

#include <iostream>
using namespace std;

// Base class definition


class Person {
public:
string name;
int age;

// Method to set the person's details


void setDetails(string n, int a) {
name = n;
age = a;
}

// Method to display person's details


void displayDetails() {
cout << "Name: " << name << ", Age: " << age << endl;
}
};

// Derived class inheriting from Person


class Student : public Person {
3|Page

public:
int rollNumber;

// Method to set roll number


void setRollNumber(int r) {
rollNumber = r;
}

// Method to display student's details


void displayStudent() {
displayDetails(); // Access base class method
cout << "Roll Number: " << rollNumber << endl;
}
};

int main() {
// Create an object of derived class
Student student1;

// Set details using base and derived class methods


student1.setDetails("John Doe", 21);
student1.setRollNumber(101);

// Display student's details


student1.displayStudent();

return 0;
}

1. Base Class (Person): This class has two public members (name and age) and two
methods:

o setDetails() sets the name and age of the person.


4|Page

o displayDetails() displays the person's information.

2. Derived Class (Student): The Student class inherits the public members of the Person
class. It adds its own member rollNumber and method setRollNumber(). It also
uses the base class’s displayDetails() function in its own method
displayStudent() to show the student's full details (including the name and age
from the Person class.

3. Inheritance: The Student class inherits everything public from the Person class. This
allows the student1 object to call both base class methods (setDetails(),
displayDetails()) and its own method (setRollNumber()).

1.2 Protected Members

In C++, protected members are class members (attributes or methods) that can only be
accessed by:

1. The class itself (the class in which they are declared),

2. Derived classes (classes that inherit from the base class where the protected members
are declared),

3. Friend classes or functions (if any are specified).

Unlike private members, protected members allow access to derived classes, which makes
them particularly useful in inheritance scenarios where derived classes need access to some of
the base class’s members, but those members should not be publicly accessible.

Key Points about Protected Members:

 Access in the same class: Protected members can be accessed within the class where
they are declared, just like private members.

 Access in derived classes: Derived classes can access protected members of the base
class.

 Access outside the class hierarchy: Protected members are not accessible outside the
class hierarchy, meaning external code (non-member functions or objects) cannot
access them directly.

Example: Using Protected Members in C++


5|Page

#include <iostream>
using namespace std;

// Base class
class Animal {
protected:
int age; // Protected member

public:
void setAge(int a) {
age = a;
}

void showAge() {
cout << "Age: " << age << endl;
}
};

// Derived class
class Dog : public Animal {
public:
void displayAge() {
cout << "Dog's Age (Accessing protected member from derived
class): " << age << endl;
}
};

int main() {
Dog myDog;
myDog.setAge(5); // Using public function to set the protected
member
myDog.showAge(); // Public function of base class displays the
protected member
6|Page

myDog.displayAge(); // Derived class accessing the protected


member

return 0;
}
1. Base Class Animal:

o The age member is declared as protected.

o A public method setAge() is provided to set the value of age, and showAge()
is used to display it.

2. Derived Class Dog:

o The derived class Dog inherits from Animal.

o In the Dog class, the displayAge() function directly accesses the protected
member age, which is allowed because Dog is a derived class of Animal.

3. In main():

o We create a Dog object and use public methods to set and display the protected
member age.

o The derived class Dog can access and display the protected age through its own
method displayAge().

1.3 Constructor and Destructor in Derived Class

In C++, when working with inheritance, both constructors and destructors of base and
derived classes play an important role in the lifecycle of objects. Understanding how
constructors and destructors behave in derived classes helps ensure that objects are initialized
and cleaned up properly.

1. Constructors in Derived Class:

When a derived class object is created, the following sequence occurs:

1. Base class constructor is called first.

2. Derived class constructor is called afterward.


7|Page

This ensures that the base class part of the derived class object is initialized before the derived
class's own initialization.

You can explicitly call a base class constructor using the initializer list in the derived class
constructor.

Example of Constructor in Derived Class:

#include <iostream>
using namespace std;

// Base class
class Base {
public:
Base() {
cout << "Base class constructor called" << endl;
}
};

// Derived class
class Derived : public Base {
public:
Derived() {
cout << "Derived class constructor called" << endl;
}
};

int main() {
Derived obj; // Object of Derived class
return 0;
}
 When the Derived class object obj is created, first the base class (Base) constructor is
called, followed by the derived class (Derived) constructor.
8|Page

 This ensures that the base part of the Derived object is properly constructed before
initializing the derived part.

2. Destructors in Derived Class:

When a derived class object is destroyed, the following sequence occurs:

1. Derived class destructor is called first.

2. Base class destructor is called afterward.

This ensures that any resources allocated in the derived class are released before cleaning up
the base class part of the object.

Example of Destructor in Derived Class:

#include <iostream>
using namespace std;

// Base class
class Base {
public:
Base() {
cout << "Base class constructor called" << endl;
}

~Base() {
cout << "Base class destructor called" << endl;
}
};

// Derived class
class Derived : public Base {
public:
Derived() {
cout << "Derived class constructor called" << endl;
9|Page

~Derived() {
cout << "Derived class destructor called" << endl;
}
};

int main() {
Derived obj; // Object of Derived class
return 0;
}
 When the object obj of the Derived class is destroyed, first the derived class destructor
is called, followed by the base class destructor.

 This ensures that the derived class cleans up its resources first, before the base class
does.

1.4 Overriding Member Functions

Overriding member functions in C++ is a feature used in inheritance where a derived class
provides a specific implementation for a member function that is already defined in its base
class. When a member function is overridden, the derived class version is executed instead of
the base class version when called on an object of the derived class. This is crucial for runtime
polymorphism and is often achieved using virtual functions.

Key Points about Overriding:

1. Inheritance: Function overriding occurs only in an inheritance relationship.

2. Same Signature: The function in the derived class must have the same signature (name,
return type, and parameters) as in the base class.

3. Virtual Function: The base class function must be declared as virtual to allow
overriding. Without the virtual keyword, function calls will be resolved at compile time
(static binding) rather than runtime (dynamic binding).
10 | P a g e

4. Runtime Polymorphism: Overriding enables runtime polymorphism, where the type


of the object (not the type of the pointer/reference) determines which function is called
at runtime.

Example of Overriding in C++:

#include <iostream>
using namespace std;

// Base class
class Animal {
public:
// Virtual function to allow overriding in derived class
virtual void sound() {
cout << "Animal makes a sound" << endl;
}
};

// Derived class
class Dog : public Animal {
public:
// Overriding the base class function
void sound() override {
cout << "Dog barks" << endl;
}
};

// Derived class
class Cat : public Animal {
public:
// Overriding the base class function
void sound() override {
cout << "Cat meows" << endl;
11 | P a g e

}
};

int main() {
Animal* animalPtr; // Pointer of base class type

Dog dog;
Cat cat;

// Point to the Dog object


animalPtr = &dog;
animalPtr->sound(); // Calls the Dog's overridden sound function

// Point to the Cat object


animalPtr = &cat;
animalPtr->sound(); // Calls the Cat's overridden sound function

return 0;
}
 Base Class (Animal): The function sound() is declared as virtual to allow it to be
overridden in the derived classes.

 Derived Classes (Dog and Cat): Both derived classes override the sound() function
from the base class to provide their own specific behavior.

 Runtime Polymorphism: A base class pointer (animalPtr) is used to point to


different derived class objects (Dog and Cat). When the sound() function is called,
the derived class version is executed based on the object type, not the pointer type.

1.5 Class Hierarchies

In C++, a class hierarchy refers to the relationship between classes when inheritance is used.
Class hierarchies are used to establish a structure where a base class provides general
functionality, and derived classes extend or modify this functionality. This concept allows for
code reuse and abstraction, promoting clean and maintainable code design.
12 | P a g e

Components of Class Hierarchies:

1. Base Class (Parent or Superclass):

o A class from which other classes (derived classes) inherit.

o It defines common functionality or properties that will be shared by its derived


classes.

o Example: In a hierarchy of vehicles, Vehicle can be the base class.

2. Derived Class (Child or Subclass):

o A class that inherits properties and behaviors from a base class.

o It can add new members or override inherited ones to provide specialized


functionality.

o Example: Car and Bike can be derived classes from the Vehicle base class.

1.6 Public, Private and Protected Inheritance

1. Public Inheritance

 In public inheritance, the access specifiers of the base class members are retained in
the derived class.

o Public members of the base class remain public in the derived class.

o Protected members of the base class remain protected in the derived class.

o Private members of the base class are not accessible in the derived class, but
they can be accessed indirectly using public or protected methods from the base
class.

Syntax:

class Derived : public Base {


// Derived class definition
};
Example:

#include <iostream>
using namespace std;
13 | P a g e

// Base class
class Base {
public:
int publicVar = 1;

protected:
int protectedVar = 2;

private:
int privateVar = 3;
};

// Derived class with public inheritance


class Derived : public Base {
public:
void display() {
cout << "Public Variable: " << publicVar << endl; //
Accessible
cout << "Protected Variable: " << protectedVar << endl; //
Accessible
// cout << privateVar; // Not accessible directly
}
};

int main() {
Derived obj;
obj.display();
cout << "Accessing publicVar from main: " << obj.publicVar <<
endl; // Allowed
return 0;
}
2. Private Inheritance
14 | P a g e

 In private inheritance, all members of the base class (public and protected) become
private in the derived class.

o Public members of the base class become private in the derived class.

o Protected members of the base class become private in the derived class.

o Private members of the base class remain inaccessible directly in the derived
class, but can still be accessed via public/protected member functions of the
base class.

Syntax:

class Derived : private Base {


// Derived class definition
};
Example:

#include <iostream>
using namespace std;

// Base class
class Base {
public:
int publicVar = 1;

protected:
int protectedVar = 2;

private:
int privateVar = 3;
};

// Derived class with private inheritance


class Derived : private Base {
public:
15 | P a g e

void display() {
cout << "Public Variable: " << publicVar << endl; //
Accessible inside class
cout << "Protected Variable: " << protectedVar << endl; //
Accessible inside class
// cout << privateVar; // Not accessible
}
};

int main() {
Derived obj;
obj.display();
// cout << obj.publicVar; // Error: publicVar is private in
Derived class
return 0;
}
3. Protected Inheritance

 In protected inheritance, the public and protected members of the base class become
protected in the derived class.

o Public members of the base class become protected in the derived class.

o Protected members of the base class remain protected in the derived class.

o Private members of the base class are not directly accessible in the derived
class.

Syntax:

class Derived : protected Base {


// Derived class definition
};
Example:

#include <iostream>
using namespace std;
16 | P a g e

// Base class
class Base {
public:
int publicVar = 1;

protected:
int protectedVar = 2;

private:
int privateVar = 3;
};

// Derived class with protected inheritance


class Derived : protected Base {
public:
void display() {
cout << "Public Variable: " << publicVar << endl; //
Accessible inside class
cout << "Protected Variable: " << protectedVar << endl; //
Accessible inside class
// cout << privateVar; // Not accessible
}
};

int main() {
Derived obj;
obj.display();
// cout << obj.publicVar; // Error: publicVar is protected in
Derived class
return 0;
}
17 | P a g e

Access Level in Public Inheritance Private Protected


Base Class Inheritance Inheritance

Public Public Private Protected

Protected Protected Private Protected


Private Not accessible Not accessible Not accessible

1.7 Types of Inheritance

There are several types of inheritance, based on how many classes are involved and how they
relate to each other.

1. Single Inheritance

 Single inheritance occurs when a derived class inherits from only one base class.

 This establishes a simple relationship between two classes.

Syntax:

class Base {
// Base class definition
};

class Derived : public Base {


// Derived class definition
};
Example:

#include <iostream>
using namespace std;

// Base class
class Animal {
public:
void eat() {
18 | P a g e

cout << "Eating..." << endl;


}
};

// Derived class
class Dog : public Animal {
public:
void bark() {
cout << "Barking..." << endl;
}
};

int main() {
Dog d;
d.eat(); // Inherited from Animal
d.bark(); // Defined in Dog
return 0;
}
2. Multiple Inheritance

 In multiple inheritance, a derived class inherits from more than one base class.

 The derived class can access the properties and behaviors of all its base classes.

Syntax:

class Base1 {
// First base class definition
};

class Base2 {
// Second base class definition
};
19 | P a g e

class Derived : public Base1, public Base2 {


// Derived class definition
};
Example:

#include <iostream>
using namespace std;

// First base class


class Engine {
public:
void start() {
cout << "Engine started..." << endl;
}
};

// Second base class


class Wheels {
public:
void rotate() {
cout << "Wheels rotating..." << endl;
}
};

// Derived class
class Car : public Engine, public Wheels {
public:
void drive() {
cout << "Car is driving..." << endl;
}
};
20 | P a g e

int main() {
Car c;
c.start(); // Inherited from Engine
c.rotate(); // Inherited from Wheels
c.drive(); // Defined in Car
return 0;
}
3. Multilevel Inheritance

 Multilevel inheritance occurs when a class is derived from another derived class.

 In this type of inheritance, there is a chain of inheritance relationships.

Syntax:

class Base {
// Base class definition
};

class Derived1 : public Base {


// Derived1 class definition
};

class Derived2 : public Derived1 {


// Derived2 class definition
};
Example:

#include <iostream>
using namespace std;

// Base class
class Animal {
public:
void eat() {
21 | P a g e

cout << "Eating..." << endl;


}
};

// Intermediate derived class


class Mammal : public Animal {
public:
void walk() {
cout << "Walking..." << endl;
}
};

// Final derived class


class Human : public Mammal {
public:
void talk() {
cout << "Talking..." << endl;
}
};

int main() {
Human h;
h.eat(); // Inherited from Animal
h.walk(); // Inherited from Mammal
h.talk(); // Defined in Human
return 0;
}
4. Hierarchical Inheritance

 In hierarchical inheritance, multiple derived classes inherit from a single base class.

 Each derived class will have access to the properties and behaviors of the base class.

Syntax:
22 | P a g e

class Base {
// Base class definition
};

class Derived1 : public Base {


// Derived1 class definition
};

class Derived2 : public Base {


// Derived2 class definition
};
Example:

#include <iostream>
using namespace std;

// Base class
class Animal {
public:
void eat() {
cout << "Eating..." << endl;
}
};

// Derived class 1
class Dog : public Animal {
public:
void bark() {
cout << "Barking..." << endl;
}
};
23 | P a g e

// Derived class 2
class Cat : public Animal {
public:
void meow() {
cout << "Meowing..." << endl;
}
};

int main() {
Dog d;
d.eat(); // Inherited from Animal
d.bark(); // Defined in Dog

Cat c;
c.eat(); // Inherited from Animal
c.meow(); // Defined in Cat
return 0;
}
5. Hybrid Inheritance

 Hybrid inheritance is a combination of two or more types of inheritance.

 It can involve combinations of single, multiple, multilevel, or hierarchical inheritance.

 This is useful in more complex class structures.

Syntax:

class Base {
// Base class definition
};

class Derived1 : public Base {


// Derived1 class definition
};
24 | P a g e

class Derived2 : public Base {


// Derived2 class definition
};

class FinalDerived : public Derived1, public Derived2 {


// Final derived class definition
};
Example:

#include <iostream>
using namespace std;

// Base class
class Animal {
public:
void eat() {
cout << "Eating..." << endl;
}
};

// Intermediate derived class 1


class Mammal : public Animal {
public:
void walk() {
cout << "Walking..." << endl;
}
};

// Intermediate derived class 2


class Bird : public Animal {
public:
25 | P a g e

void fly() {
cout << "Flying..." << endl;
}
};

// Final derived class


class Bat : public Mammal, public Bird {
public:
void hang() {
cout << "Hanging upside down..." << endl;
}
};

int main() {
Bat b;
b.eat(); // Can eat because Bat is both Mammal and Bird
b.walk(); // Inherited from Mammal
b.fly(); // Inherited from Bird
b.hang(); // Defined in Bat
return 0;
}
1.8 Ambiguity in Multiple Inheritance

In C++, ambiguity can occur in multiple inheritance when two or more base classes contain
methods or members with the same name, and a derived class inherits from both. The compiler
gets confused about which method or member to use, as it cannot decide which one to call
without further clarification.

When a class inherits from multiple base classes, and both base classes have a member function
or variable with the same name, calling this function or accessing this variable in the derived
class will result in ambiguity.

Resolving Ambiguity

There are several ways to resolve ambiguity in multiple inheritance.


26 | P a g e

1. Using Scope Resolution Operator

We can use the scope resolution operator (::) to specify which base class’s member function
or variable to use.

Example:

#include <iostream>
using namespace std;

// Base class 1
class A {
public:
void show() {
cout << "Show from class A" << endl;
}
};

// Base class 2
class B {
public:
void show() {
cout << "Show from class B" << endl;
}
};

// Derived class inherits from both A and B


class C : public A, public B {
};

int main() {
C obj;
obj.A::show(); // Calls show() from class A
obj.B::show(); // Calls show() from class B
27 | P a g e

return 0;
}
2. Virtual Inheritance

In the case where both base classes derive from a common ancestor (grandparent class), we
can use virtual inheritance to avoid multiple copies of the grandparent's members in the
derived class.

#include <iostream>
using namespace std;

class Base {
public:
int value;
};

class A : public virtual Base {


};

class B : public virtual Base {


};

class C : public A, public B {


};

int main() {
C obj;
obj.value = 10; // No ambiguity due to virtual inheritance
cout << obj.value << endl;
return 0;
}
In this case, virtual inheritance ensures that only one copy of Base exists in C, resolving the
ambiguity.
28 | P a g e

1.9 Abstract class

An abstract class in C++ is a class that cannot be instantiated (i.e., you cannot create objects
of an abstract class). It is primarily used as a base class for other classes to inherit from. An
abstract class is declared when it contains at least one pure virtual function.

A pure virtual function is a virtual function that has no definition in the base class. It is meant
to be overridden by derived classes, and its syntax is defined using = 0 at the end of the function
declaration.

Syntax of Abstract Class:

class AbstractClass {
public:
virtual void pureVirtualFunction() = 0; // Pure virtual function
};
Example:

Suppose you are creating a program to model different types of employees in a company. The
base class Employee could be an abstract class because every employee should have a function
to calculate their salary, but the specific implementation of that function will differ for different
types of employees like Manager, Engineer, etc.

#include <iostream>
using namespace std;

// Abstract base class


class Employee {
public:
virtual void calculateSalary() = 0; // Pure virtual function
};

// Derived class
class Manager : public Employee {
public:
void calculateSalary() override {
29 | P a g e

cout << "Calculating salary for Manager." << endl;


}
};

// Derived class
class Engineer : public Employee {
public:
void calculateSalary() override {
cout << "Calculating salary for Engineer." << endl;
}
};

int main() {
// Employee emp; // Error: Cannot instantiate an abstract class

Manager m;
Engineer e;

m.calculateSalary(); // Calls Manager's implementation


e.calculateSalary(); // Calls Engineer's implementation

return 0;
}
1.10 Friend Class

In C++, a friend class is a class that is granted access to the private and protected members of
another class. Even though private and protected members are usually accessible only within
the class they are declared, a friend class breaks this rule and allows access to these members.

Syntax of Friend Class:

class A {
friend class B; // Class B is a friend of class A
private:
30 | P a g e

int secretValue;
};
In this example, class B is a friend of class A and can access the private members of class A,
like secretValue.

Example of Friend Class:

#include <iostream>
using namespace std;

class A {
private:
int privateData; // Private member of class A
public:
A() : privateData(42) {} // Constructor to initialize privateData
// Declaring class B as a friend of class A
friend class B;
};

class B {
public:
void showPrivateData(A& objA) {
// B can access private members of A
cout << "Private Data of A: " << objA.privateData << endl;
}
};

int main() {
A objA; // Create an object of class A
B objB; // Create an object of class B
objB.showPrivateData(objA); // B can access A's private data
return 0;
}
31 | P a g e

 Class A has a private member privateData.

 Class B is declared as a friend class of A. This allows B to access the private members
of A.

 In the showPrivateData function of B, it directly accesses the privateData of class


A, which is normally restricted.

 In main(), an object of B (objB) accesses and displays the private data of an object of
A (objA).

1.11 Nested Class

A nested class in C++ is a class defined within another class. The enclosing class is called the
outer class, and the class defined inside it is the nested class. A nested class is a member of
the outer class and has access to the private and protected members of the outer class (if it’s a
regular nested class and not a static nested class).

Syntax of Nested Class:

class OuterClass {
class NestedClass {
// Members of the nested class
};
// Members of the outer class
};
Example of Nested Class:

Consider a Car class that contains an engine. You can define an Engine class as a nested
class inside the Car class, since the Engine class logically belongs to the Car.

#include <iostream>
using namespace std;

// Outer class Car


class Car {
public:
// Nested class Engine
32 | P a g e

class Engine {
public:
void startEngine() {
cout << "Engine started" << endl;
}
};

void startCar() {
engine.startEngine();
cout << "Car started" << endl;
}

private:
Engine engine; // Composition: Car has an Engine
};

int main() {
Car myCar; // Create a Car object
myCar.startCar(); // Start the car (and its engine)

return 0;
}
 The Engine class is nested within the Car class because it is closely related and serves
as part of the Car.
 Car has a private member engine of type Engine, and its method startCar() calls
the nested class’s startEngine() method.

2. Pointers
In C++, a pointer is a variable that holds the memory address of another variable. Pointers are
a powerful feature that allows direct memory manipulation and dynamic memory management.

2.1 Declaring and Initializing Pointers


33 | P a g e

Declaring a Pointer:

To declare a pointer, you specify the type of the variable it will point to, followed by an asterisk
(*), and then the pointer's name.

type *pointerName;

 type: The data type of the variable that the pointer will point to.

 pointerName: The name of the pointer variable.

Example of Pointer Declaration:

int *p; // p is a pointer to an integer

char *ch; // ch is a pointer to a character

float *f; // f is a pointer to a float

Initializing a Pointer:

After declaring a pointer, you can initialize it by assigning it the address of a variable. The
address-of operator (&) is used to obtain the address of a variable.

Syntax:

pointerName = &variable;

Example of Pointer Initialization:

int num = 10; // Variable of type int

int *p = &num; // Pointer p holds the address of num

In this example, p is a pointer to an integer, and it stores the memory address of the variable
num.

2.2 Indirection Operator (Dereference Operator)

The indirection operator allows you to access or modify the value stored at the memory
address held by the pointer. When used with a pointer, it refers to the value at the pointer's
address.

Syntax:

*pointer
34 | P a g e

Example:

#include <iostream>
using namespace std;

int main() {
int num = 10;
int *ptr = &num; // 'ptr' holds the address of 'num'

// Using indirection operator to access the value of 'num'


cout << "Value of num through pointer: " << *ptr << endl; //
Outputs: 10

// Modifying value using indirection


*ptr = 20; // Changing the value of 'num' through the pointer
cout << "New value of num: " << num << endl; // Outputs: 20

return 0;
}
 The pointer ptr holds the address of num.

 Using *ptr, we access the value stored at that address (num in this case), which is 10.

 By using *ptr = 20, we change the value of num to 20.

2.3 Memory Management: New and Delete

In C++, dynamic memory management is handled through the operators new and delete.
These operators allow you to allocate and deallocate memory manually during the program's
execution, which is essential for creating variables or arrays whose size may not be known until
runtime.

1. new Operator:

The new operator dynamically allocates memory on the heap (free store) and returns a pointer
to the beginning of the newly allocated memory. It can be used to allocate memory for both
single variables and arrays.
35 | P a g e

Syntax:

pointer = new type; // For single variable allocation


pointer = new type[size]; // For array allocation
Example of Alloca ng Memory for a Single Variable:

int *ptr = new int; // Allocates memory for one integer on the heap
*ptr = 10; // Assigns a value to the dynamically allocated memory
cout << "Value: " << *ptr << endl; // Outputs: 10
Example of Alloca ng Memory for an Array:

int *arr = new int[5]; // Allocates memory for an array of 5 integers


on the heap
// Assigning values to the array
for (int i = 0; i < 5; i++) {
arr[i] = i + 1;
}
// Printing the array values
for (int i = 0; i < 5; i++) {
cout << arr[i] << " "; // Outputs: 1 2 3 4 5
}

2. delete Operator:

The delete operator is used to free the dynamically allocated memory and avoid memory
leaks. You should call delete to deallocate the memory that was allocated with new.

Syntax:

delete pointer; // For single variable deallocation


delete[] pointer; // For array deallocation

Example of Memory Management

#include <iostream>
using namespace std;

int main() {
36 | P a g e

// Dynamically allocate memory for a single integer


int *num = new int;
*num = 42; // Assign value

cout << "Value of num: " << *num << endl; // Outputs: 42

// Dynamically allocate memory for an array of 3 integers


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

// Output array values


cout << "Array values: ";
for (int i = 0; i < 3; i++) {
cout << arr[i] << " "; // Outputs: 0 10 20
}
cout << endl;

// Free the allocated memory


delete num; // Deallocate single integer memory
delete[] arr; // Deallocate array memory

return 0;
}
2.4 Pointers to Objects

In C++, pointers to objects are similar to pointers to basic data types, but they point to
instances (objects) of a class. Pointers to objects allow you to dynamically manage objects,
access their member variables and methods, and perform various operations at runtime.

Declaring Pointers to Objects:


37 | P a g e

To declare a pointer to an object, you specify the class name, followed by an asterisk (*), and
then the pointer variable name. The pointer can then store the address of an object of that class.

Syntax:

ClassName *pointerName;

Creating an Object and Assigning Its Address to the Pointer:

 You can use the address-of operator (&) to get the address of an object and assign it
to a pointer.

 You can also dynamically create an object using the new operator.

Example:

class Student {
public:
string name;
int rollNo;

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

int main() {
Student s1; // Create an object of class Student
Student *ptr = &s1; // Pointer to the object

// Accessing members through the pointer


ptr->name = "Haris"; // Using the arrow operator (->)
ptr->rollNo = 101;

// Call member function using the pointer


ptr->display(); // Outputs: Name: Haris, Roll No: 101
38 | P a g e

return 0;
}
 Student *ptr = &s1; creates a pointer ptr that stores the address of the object s1.

 ptr->name and ptr->rollNo access the member variables through the pointer using
the arrow operator (->).

 ptr->display() calls the display() method through the pointer.

2.5 this Pointer

In C++, the this pointer is an implicit pointer available within a class's member functions. It
points to the object for which the member function is called. The this pointer is particularly
useful in situations where you need to refer to the calling object's members, especially in cases
of naming conflicts or when you want to return the current object from a member function.

Usage of this Pointer:

1. Accessing Members: You can use this to explicitly access member variables and
functions, which is especially helpful when parameter names shadow member names.

2. Returning the Current Object: You can return *this to enable method chaining.

3. Distinguishing Between Parameters and Members: When member variables and


parameters have the same name, this can be used to clarify which is which.

Example of this Pointer:

#include <iostream>
using namespace std;

class Rectangle {
private:
int width, height;

public:
// Constructor
Rectangle(int width, int height) {
39 | P a g e

this->width = width; // 'this' distinguishes member from


parameter
this->height = height;
}

// Function to calculate area


int area() {
return this->width * this->height; // Using 'this' (optional)
}

// Function to return current object (method chaining)


Rectangle& setDimensions(int width, int height) {
this->width = width;
this->height = height;
return *this; // Return current object
}

void display() {
cout << "Width: " << width << ", Height: " << height << endl;
}
};

int main() {
Rectangle rect(10, 5); // Create an object
rect.display(); // Outputs: Width: 10, Height: 5

cout << "Area: " << rect.area() << endl; // Outputs: Area: 50

// Method chaining
rect.setDimensions(20, 10).display(); // Outputs: Width: 20,
Height: 10
40 | P a g e

return 0;
}
 Constructor: The Rectangle constructor takes parameters width and height. The this
pointer is used to distinguish between the member variables and the parameters,
resolving any ambiguity.
 Method Chaining: The setDimensions function modifies the dimensions of the
rectangle and returns the current object (*this), allowing for method chaining.
 Accessing Members: In the area function, this->width and this->height access the
member variables. While using this is optional here, it can enhance clarity.

2.6 Pointers Vs Arrays

Sr No. Pointers Arrays


1. A pointer is a place in memory that An array is a single, pre-allocated chunk of
points to the address of a variable. contiguous elements (all of the same type),
fixed in size and location.
2. A pointer cannot be initialized at the An array can be initialized at definition.
definition. Example: int num[] = {2, 4, 5}
3. A pointer is dynamic in nature. The They are static in nature. Once the memory
memory allocation can be resized or is allocated, it cannot be resized or freed
freed later. dynamically.
4. When using the sizeof() operator When used on a pointer, sizeof() returns
on a fixed array, sizeof() returns the size of a memory address (in bytes).
the size of the entire array (array
length * element size).
5. Syntax: Syntax:
type var_name[size]; type *var_name;

2.7 Pointers Vs References

Sr No. Pointers References


1. A variable that stores the memory An alias for another variable.
address of another variable.
41 | P a g e

2. Can be assigned a null value (e.g., Cannot be null. Must always refer to a valid
nullptr) object.
3. sizeof(ptr) gives size of the sizeof(ref) is the same as
pointer itself, not the object it sizeof(var) since references are not
points to. objects.

4. Allows arithmetic operations (e.g., No pointer arithmetic.


ptr + 1).

5. Functions can return pointers (e.g., Functions can return references (e.g.,
int* createPointer()). int& getReference()).

6. Syntax: int* ptr; Syntax: int& ref;

2.8 Accessing Arrays using Pointers

In C++, arrays and pointers are closely related. The name of an array acts like a pointer to the
first element of the array. This allows you to access and manipulate arrays using pointers.

Basic Concept:

 The name of an array, such as arr, is a constant pointer to the first element of the array
(i.e., &arr[0]).

 Pointers can be used to iterate over the elements of the array using pointer arithmetic.

Accessing Array Elements Using Pointers:

1. Array Name as a Pointer: The name of the array points to the address of the first element.

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


int *ptr = arr; // arr is the same as &arr[0]
2. Pointer Arithmetic: You can access the elements of the array by incrementing the pointer.

 ptr + 1 points to the second element.

 ptr + 2 points to the third element, and so on.

 Dereferencing the pointer (*ptr) gives the value at the memory location pointed to.

Example: Accessing Array Using Pointers:


42 | P a g e

#include <iostream>
using namespace std;

int main() {
int arr[5] = {10, 20, 30, 40, 50};
int *ptr = arr; // Pointer to the first element of the array

// Accessing elements using the pointer


for (int i = 0; i < 5; i++) {
cout << "Element " << i + 1 << ": " << *(ptr + i) << endl;
// *(ptr + i) gives the value at arr[i]
}

return 0;
}
2.9 Arrays of Pointers

In C++, arrays of pointers refer to an array where each element is a pointer. This means that
instead of storing data like integers, characters, or other types directly, the array stores
addresses (pointers) that point to data stored elsewhere in memory.

Key Points:

1. An array of pointers can store multiple addresses, each pointing to a different object or
variable.

2. The pointers in the array can be of any data type (e.g., int, char, double, or even
user-defined types like objects).

3. This is especially useful when you want to dynamically allocate memory for each
element or work with strings, objects, or complex data structures.

Declaring an Array of Pointers:

The syntax for declaring an array of pointers is similar to declaring a regular array, but with an
asterisk (*) indicating that the elements of the array are pointers.
43 | P a g e

Syntax:

DataType* arrayName[size];

Example: Array of Pointers to Integers:

#include <iostream>
using namespace std;

int main() {
// Declare an array of 3 integer pointers
int *arr[3];

// Create three integers


int a = 10, b = 20, c = 30;

// Store the addresses of the integers in the array of pointers


arr[0] = &a;
arr[1] = &b;
arr[2] = &c;

// Access the values using the array of pointers


for (int i = 0; i < 3; i++) {
cout << "Value at arr[" << i << "] = " << *arr[i] << endl;
}

return 0;
}
 int *arr[3]; : This declares an array arr of three integer pointers.
 arr[0] = &a; : The first element of the array arr[0] stores the address of a.
 *arr[i] : Dereferencing each pointer retrieves the value stored at that memory
location (e.g., *arr[0] gives the value of a).

2.10 Function Pointers


44 | P a g e

Function pointers in C++ are pointers that point to the address of a function instead of a
variable or an object. This allows you to dynamically call functions, pass them as arguments to
other functions, or store them in arrays or data structures.

1. Declaration of Function Pointers

To declare a function pointer, you need to specify the return type and the parameter types that
match the function the pointer will point to.

Syntax:

ReturnType (*PointerName)(ParameterType1, ParameterType2, ...);

2. Referencing (Assigning a Function to a Pointer)

Referencing in the context of function pointers means assigning the address of a function to
the function pointer. You can use the & operator.

PointerName = &FunctionName;

3. Dereferencing (Calling a Function Using a Function Pointer)

Dereferencing a function pointer involves calling the function it points to. You can call the
function by dereferencing the pointer using (*PointerName)(arguments)

Syntax:

(*PointerName)(arguments); // Dereferencing

Complete Example with Declaration, Referencing, and Dereferencing:

#include <iostream>
using namespace std;

// Function that adds two integers


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

int main() {
// Step 1: Declaration of function pointer
45 | P a g e

int (*funcPtr)(int, int);

// Step 2: Referencing (Assigning a function to the pointer)


funcPtr = &add;

// Step 3: Dereferencing (Calling the function using the pointer)


int result = (*funcPtr)(10, 20);

// Output the result


cout << "Result of addition: " << result << endl; // Output: 30

return 0;
}
2.11 Pointers to Pointers

In C++, a pointer to a pointer is a type of pointer that stores the address of another pointer.
Essentially, it is a pointer that points to another pointer, which in turn points to the actual data.

Concept:

 A pointer stores the address of a variable.

 A pointer to a pointer stores the address of another pointer.

Syntax of Pointer to a Pointer

To declare a pointer to a pointer, use the following syntax:

DataType **PointerName;

Here,

 DataType: The type of data the final pointer will point to.

 PointerName: The name of the pointer to pointer.

Example: Pointer to a Pointer

#include <iostream>
using namespace std;
46 | P a g e

int main() {
int var = 10; // A normal integer variable
int *ptr = &var; // A pointer to the integer variable
int **pptr = &ptr; // A pointer to the pointer

// Displaying the values


cout << "Value of var: " << var << endl; // Output: 10
cout << "Value using *ptr: " << *ptr << endl; // Output: 10
cout << "Value using **pptr: " << **pptr << endl; // Output: 10

// Displaying the addresses


cout << "Address of var: " << &var << endl;
cout << "Address stored in ptr: " << ptr << endl;
cout << "Address stored in pptr: " << pptr << endl;

return 0;
}
 var: A normal integer variable.

 ptr: A pointer to var (ptr stores the address of var).

 pptr: A pointer to ptr (pptr stores the address of ptr).

When we dereference pptr (**pptr), we are essentially following two pointers to reach the
value of var. The first dereference (*pptr) gives us the value of ptr (which is the address of
var), and the second dereference (**pptr) gives us the value of var.

2.12 Pointers to Derived Classes

In C++, when using inheritance, you can have pointers to base class objects that can also point
to derived class objects. However, there are some important rules and behaviors to keep in
mind, especially when dealing with polymorphism and the behavior of virtual functions.

Concept:
47 | P a g e

 A pointer to a base class can point to an object of the derived class.

 However, using base class pointers to access derived class-specific members requires
type casting.

 If a base class has virtual functions, they can be overridden in the derived class, and
the virtual mechanism ensures that the correct function is called even when accessed
through a base class pointer.

Syntax:

BaseClass *ptr;

You can use ptr to point to an object of either the BaseClass or any of its derived classes.

#include <iostream>
using namespace std;

// Base class
class Base {
public:
void show() {
cout << "Base class show function called." << endl;
}
};

// Derived class
class Derived : public Base {
public:
void show() {
cout << "Derived class show function called." << endl;
}
};

int main() {
Base baseObj;
48 | P a g e

Derived derivedObj;

// Base class pointer


Base *basePtr;

// Pointing to base class object


basePtr = &baseObj;
basePtr->show(); // Output: Base class show function called.

// Pointing to derived class object


basePtr = &derivedObj;
basePtr->show(); // Output: Base class show function called (Not
Derived class)

return 0;
}
 The basePtr is a pointer to Base, but it can also point to Derived because Derived
is derived from Base.

 Even though basePtr points to a Derived object in the second case, the Base class
version of show() is called. This is because the call is made through a base class
pointer, and without virtual functions, the base class method is called.

2.13 Passing Pointers to Functions

In C++, passing pointers to functions is a common technique used to modify variables outside
the function’s scope or to handle arrays efficiently. By passing the address of a variable rather
than its value, you allow the function to directly manipulate the original variable.

Syntax:

ReturnType functionName(DataType *pointerName);

Example:

#include <iostream>
using namespace std;
49 | P a g e

// Function that takes a pointer to an int


void increment(int *ptr) {
(*ptr)++; // Dereference the pointer and increment the value
}

int main() {
int num = 10;

// Pass the address of num to the function


increment(&num);

// Output the incremented value


cout << "Incremented value: " << num << endl; // Output: 11

return 0;
}
 Function: increment() accepts a pointer to an integer (int *ptr).

 Pointer Dereferencing: Inside the function, the pointer ptr is dereferenced (*ptr) to
access and modify the value of the variable it points to.

 Main Function: The address of the variable num is passed to the increment()
function using &num, allowing the function to modify the original num variable directly.

2.14 Return Pointers from Functions

In C++, functions can return pointers. This technique is useful when a function needs to return
the address of a variable, an array, or dynamically allocated memory.

Concept:

1. Local Variables: Returning pointers to local variables is dangerous because local


variables are destroyed when the function exits.
50 | P a g e

2. Dynamically Allocated Memory: Functions can return pointers to memory that has
been dynamically allocated (using new), allowing the memory to persist after the
function exits.

3. Global or Static Variables: Pointers to global or static variables can safely be returned
because their lifetime extends beyond the function.

Syntax:

DataType* functionName() {
// function body
}
Example:

#include <iostream>
using namespace std;

// Function to return a pointer to a dynamically allocated integer


int* createInt() {
// Dynamically allocate memory for an integer
int* ptr = new int;
*ptr = 42; // Assign a value to the allocated memory
return ptr; // Return the pointer
}

int main() {
// Call the function and get the pointer
int* p = createInt();

// Use the returned pointer


cout << "Value: " << *p << endl; // Output: 42

// Free the allocated memory


delete p;
51 | P a g e

return 0;
}
Explanation:

 The function createInt() returns a pointer to a dynamically allocated integer.

 In main(), the pointer p holds the address returned by createInt(), and the value
stored at that address is printed.

 The memory allocated with new must be released using delete to avoid memory leaks.

2.15 Null Pointer

A null pointer is a pointer that doesn’t point to any valid memory location. In C++, a null
pointer is represented by the constant nullptr.

Why Use Null Pointers?

 To initialize pointers to indicate they don't point to any memory yet.

 To check if a pointer has been assigned a valid memory location.

 To avoid dangling pointers (pointers that point to memory that has already been freed
or is invalid).

Syntax:

int* ptr = nullptr;

Example:

#include <iostream>
using namespace std;

int main() {
int* ptr = nullptr; // Pointer initialized to null

if (ptr == nullptr) {
cout << "Pointer is null." << endl;
} else {
52 | P a g e

cout << "Pointer is not null." << endl;


}

return 0;
}
 The pointer ptr is initialized to nullptr, indicating that it does not point to any valid
memory location.
 The if statement checks if ptr is null, and the output confirms it.

2.16 Void Pointer

A void pointer (or void*) is a special type of pointer that can point to any data type. It is a
generic pointer that doesn't have a specific data type associated with it, which makes it useful
for functions and operations that need to handle different data types.

Characteristics of Void Pointers:

1. Generic Pointers: void* can be assigned to any other pointer type without an explicit
cast.

2. No Dereferencing: You cannot dereference a void* directly because the compiler does
not know what type of data it points to. You must cast it to another pointer type before
dereferencing.

3. Memory Operations: Useful for implementing functions that need to operate on


different data types generically.

Syntax:

void* ptr; // Declaration of a void pointer

Example:

#include <iostream>
using namespace std;

int main() {
int num = 10;
double pi = 3.14;
53 | P a g e

void* ptr; // Declare a void pointer

ptr = &num; // Assign address of int variable to void pointer


cout << "Value of num: " << *(static_cast<int*>(ptr)) << endl;
// Cast and dereference

ptr = &pi; // Assign address of double variable to void pointer


cout << "Value of pi: " << *(static_cast<double*>(ptr)) << endl;
// Cast and dereference

return 0;
}
 void* ptr is a generic pointer that can point to any type.
 To use ptr, you need to cast it to the appropriate pointer type before dereferencing it.
 static_cast<int*>(ptr) casts ptr to an int* so that it can be dereferenced to
access the integer value.
 Similarly, static_cast<double*>(ptr) casts ptr to a double*.

You might also like