OOP Unit 2 Notes
OOP Unit 2 Notes
OOP Unit 2 Notes
Unit – II
Inheritance and Pointers
1. Inheritance
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).
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 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
};
#include <iostream>
using namespace std;
public:
int rollNumber;
int main() {
// Create an object of derived class
Student student1;
return 0;
}
1. Base Class (Person): This class has two public members (name and age) and two
methods:
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()).
In C++, protected members are class members (attributes or methods) that can only be
accessed by:
2. Derived classes (classes that inherit from the base class where the protected members
are declared),
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.
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.
#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
return 0;
}
1. Base Class Animal:
o A public method setAge() is provided to set the value of age, and showAge()
is used to display it.
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().
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.
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.
#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.
This ensures that any resources allocated in the derived class are released before cleaning up
the base class part of the object.
#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.
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.
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
#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;
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.
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
o Example: Car and Bike can be derived classes from the Vehicle base class.
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:
#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;
};
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:
#include <iostream>
using namespace std;
// Base class
class Base {
public:
int publicVar = 1;
protected:
int protectedVar = 2;
private:
int privateVar = 3;
};
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:
#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;
};
int main() {
Derived obj;
obj.display();
// cout << obj.publicVar; // Error: publicVar is protected in
Derived class
return 0;
}
17 | P a g e
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.
Syntax:
class Base {
// Base class definition
};
#include <iostream>
using namespace std;
// Base class
class Animal {
public:
void eat() {
18 | P a g e
// 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
#include <iostream>
using namespace std;
// 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.
Syntax:
class Base {
// Base class definition
};
#include <iostream>
using namespace std;
// Base class
class Animal {
public:
void eat() {
21 | P a g e
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
};
#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
Syntax:
class Base {
// Base class definition
};
#include <iostream>
using namespace std;
// Base class
class Animal {
public:
void eat() {
cout << "Eating..." << endl;
}
};
void fly() {
cout << "Flying..." << 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
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;
}
};
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;
};
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
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.
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;
// Derived class
class Manager : public Employee {
public:
void calculateSalary() override {
29 | P a g e
// 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;
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.
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.
#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 B is declared as a friend class of A. This allows B to access the private members
of A.
In main(), an object of B (objB) accesses and displays the private data of an object of
A (objA).
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).
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;
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.
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.
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;
In this example, p is a pointer to an integer, and it stores the memory address of the variable
num.
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 = # // 'ptr' holds the address of 'num'
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.
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:
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:
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:
#include <iostream>
using namespace std;
int main() {
36 | P a g e
cout << "Value of num: " << *num << endl; // Outputs: 42
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.
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;
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
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 (->).
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.
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.
#include <iostream>
using namespace std;
class Rectangle {
private:
int width, height;
public:
// Constructor
Rectangle(int width, int height) {
39 | P a g e
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. 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.
5. Functions can return pointers (e.g., Functions can return references (e.g.,
int* createPointer()). int& getReference()).
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.
1. Array Name as a Pointer: The name of the array points to the address of the first element.
Dereferencing the pointer (*ptr) gives the value at the memory location pointed to.
#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
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.
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];
#include <iostream>
using namespace std;
int main() {
// Declare an array of 3 integer pointers
int *arr[3];
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).
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.
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:
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;
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
#include <iostream>
using namespace std;
int main() {
// Step 1: Declaration of function pointer
45 | P a g e
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:
DataType **PointerName;
Here,
DataType: The type of data the final pointer will point to.
#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
return 0;
}
var: A normal integer variable.
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.
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
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;
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.
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:
Example:
#include <iostream>
using namespace std;
49 | P a g e
int main() {
int num = 10;
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.
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:
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;
int main() {
// Call the function and get the pointer
int* p = createInt();
return 0;
}
Explanation:
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.
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.
To avoid dangling pointers (pointers that point to memory that has already been freed
or is invalid).
Syntax:
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
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.
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.
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.
Syntax:
Example:
#include <iostream>
using namespace std;
int main() {
int num = 10;
double pi = 3.14;
53 | P a g e
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*.