0% found this document useful (0 votes)
6 views78 pages

OOP Notes

The document explains constructors and destructors in C++, detailing their definitions, properties, and usage. Constructors initialize objects upon creation, while destructors clean up resources when objects are destroyed. It also covers memory management for stack and heap allocations, the different types of constructors, and the importance of proper memory management to avoid leaks.

Uploaded by

mehwish.kiran
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views78 pages

OOP Notes

The document explains constructors and destructors in C++, detailing their definitions, properties, and usage. Constructors initialize objects upon creation, while destructors clean up resources when objects are destroyed. It also covers memory management for stack and heap allocations, the different types of constructors, and the importance of proper memory management to avoid leaks.

Uploaded by

mehwish.kiran
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Notes

Constructors And Destructors In C++

1. Object Must Be in a Deterministic State

▪ An object should have a defined state when one of its data members changes.

▪ There must be:

▪ An initial state (Initialize function: Constructor) when an object is created.


▪ A finish state (destroy function: Destructor) to properly clean up
resources when an object is destroyed.
2. Constructors: Creation and Initialization

Definition
A constructor is a special function in a class that is automatically called
when an object is created. Its primary purpose is to initialize data
members.

Properties of a Constructor
▪ Same name as the class.
▪ No return type (not even void).
▪ Automatically called when an object is created.

class shoplist {
public:
shoplist() {
count = 0;
}
};
▪ The constructor shoplist() is automatically called when an object is
created.
▪ It initializes count to 0.
Parameterized Constructor
A constructor can take arguments to initialize an object with specific
values.
class A {
public:
string c;

A(string e)
{
c = e;
}
};
▪ A(string e) is a constructor with a parameter.
▪ It initializes c with the value passed as e.

A obj("hello c++");
▪ The object obj is created, and its c member is initialized with "hello c++".
Stack Allocation
When an object is created without new, it is allocated on the stack.

A a1;
A a2;

▪ Here, a1 and a2 are created on the stack.


▪ Memory is automatically managed; when the function ends, the objects
are destroyed.

Heap Allocation
When an object is created using new, it is allocated on the heap.

A *c = new A("hello");

▪ The object is allocated dynamically.


▪ It remains in memory until delete is explicitly called.
4. Destructors
A destructor is a special function that is automatically called when an
object is destroyed.

Properties of a Destructor

▪ Same name as the class, but preceded by a tilde (~).


▪ No return type.
▪ No parameters.
▪ Called automatically when an object is destroyed.

Example Destructor

class A {
public:
~A() {
cout << "Destructor called";
}
};

▪ This destructor will print a message when an object is destroyed.


Destructor Call in Stack vs Heap

[Link] Objects

int main() {
A a1;
A b1;
}
▪ The destructors for a1 and b1 are automatically called when main() ends.

[Link] Objects

int main() {
A *c = new A("hello");
delete c; // Destructor called here
}

Since c is created on the heap, it must be explicitly deleted.


•If delete c; is omitted, there will be a memory leak.
When is a Constructor Called in C++?

A constructor is automatically called when an object of a class is created.


The constructor is responsible for initializing the object.

Different Ways of Calling Constructors


▪ Implicit Call
▪ Explicit Call
▪ Copy Initialization
▪ Direct Initialization

Scenarios When a Constructor is Called

1. When a Local (Stack) Object is Created

▪ If an object is created without new, the constructor is called immediately.

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

int main() {
A obj; // Constructor is called automatically
}
▪ Output: Constructor called
2. When a Heap Object is Created Using new

▪ If an object is created dynamically using new, the constructor is called.

A* obj = new A(); // Constructor is called

▪ The object remains in memory until explicitly deleted using delete.


3. When an Object is Created with a Parameterized Constructor

▪ If a class has a constructor with parameters, it is called when an object is initialized with arguments.

class A {
public:
A(string msg) { cout << "Constructor called with: " << msg << endl; }
};

int main() {
A obj("Hello"); // Parameterized constructor is called
}

▪ Output: Constructor called with: Hello


4. When an Array of Objects is Created

▪ If an array of objects is created, the constructor is called for each object.

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

int main() {
A arr[3]; // Constructor is called 3 times
}

▪ Output:

Constructor called
Constructor called
Constructor called
5. When an Object is Passed by Value

▪ When an object is passed by value, the copy constructor is called.

class A {
public:
A() { cout << "Default Constructor called" << endl; }
A(const A& obj) { cout << "Copy Constructor called" << endl; }
};

void func(A obj) { } // Copy constructor is called

int main() {
A a1; // Default constructor is called
func(a1); // Copy constructor is called
}

▪ Output:

Default Constructor called


Copy Constructor called
6. When an Object is Returned by Value

▪ When a function returns an object by value, the copy constructor is called.

A func() {
A temp;
return temp;
}
int main() {
A obj = func(); // Copy constructor is called
}
7. When an Object is Created Using Another Object

▪ If an object is initialized using another object, the copy constructor is called.

A obj1;
A obj2 = obj1; // Copy constructor is called
▪ Constructors initialize objects automatically when they are created.

▪ Parameterized constructors allow passing values at creation.

▪ Objects created on the stack are automatically managed.

▪ Objects created on the heap must be manually deleted.

▪ Destructors clean up resources when an object is destroyed.

▪ If heap memory is not freed using delete, memory leaks occur.

▪ Constructor is called when an object is created.

▪ For stack objects, it is called immediately.

▪ For heap objects (new), it is called during allocation.

▪ For parameterized constructors, values are passed at creation.

▪ Copy constructor is called when passing or returning objects by value.

▪ For arrays, the constructor is called once per object in the array.
When is a Constructor Not Called in C++?

A constructor is not called in the following scenarios:

When Using Pointers Without new

If you declare a pointer to an object without using new, the constructor is not called.

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

int main() {
A* obj; // Constructor is NOT called (only a pointer is declared)
}

Why?
▪ obj is just a pointer to an object, but no actual object is created.
▪ The constructor is only called when an object is instantiated, not just when a pointer is declared.
Types of constructors in C++:
Default Constructor
▪ A constructor that takes no parameters and initializes the object with default values.

class Point {
public:
int x, y;
Point() { x = 0; y = 0; } // Default constructor
};

Parameterized Constructor
▪ A constructor that takes arguments to initialize the object with specific values.

class Point {
public:
int x, y;
Point(int a, int b) { x = a; y = b; } // Parameterized constructor
};

Copy Constructor
▪ A constructor that creates a new object by copying an existing object.

class Point {
public:
int x, y;
Point(int a, int b) { x = a; y = b; }
Point(const Point &p) { x = p.x; y = p.y; } // Copy constructor
};
Calling Default Constructor
▪ The default constructor is automatically called when an object is created without passing any arguments.

class Point {
public:
int x, y;

// Default Constructor
Point() {
x = 0;
y = 0;
cout << "Default Constructor Called" << endl;
}
};

int main() {
Point p1; // Calls Default Constructor
return 0;
}
Calling Parameterized Constructor
▪ The parameterized constructor is called when an object is created with arguments.

class Point {
public:
int x, y;

// Parameterized Constructor
Point(int a, int b) {
x = a;
y = b;
cout << "Parameterized Constructor Called" << endl;
}
};

int main() {
Point p2(10, 20); // Calls Parameterized Constructor
return 0;
}
Calling Copy Constructor
▪ The copy constructor is called when a new object is initialized from an existing object.

class Point {
public:
int x, y;

// Parameterized Constructor
Point(int a, int b) {
x = a;
y = b;
}

// Copy Constructor
Point(const Point &p) {
x = p.x;
y = p.y;
cout << "Copy Constructor Called" << endl;
}
};

int main() {
Point p3(5, 15); // Calls Parameterized Constructor
Point p4 = p3; // Calls Copy Constructor
return 0;
}
Destructors in C++

A destructor is a special member function of a class that is automatically invoked when an object
goes out of scope or is explicitly deleted.

Properties of Destructors:

▪ Same name as class, prefixed with ~ (tilde).


▪ No arguments allowed (i.e., destructors cannot be overloaded).
▪ Automatically called when an object is destroyed.
▪ Mainly used for cleanup, such as releasing dynamically allocated memory.
class A {
public:
A() {
cout << "Constructor A\n"; Output:
}
~A() { Constructor A
cout << "Destructor A\n"; Destructor A
}
};

int main() {
A obj; // Constructor called
return 0; // Destructor called when obj goes out of scope
}
Heap Allocation and Destructor

If an object is dynamically allocated using new, its destructor is not called automatically.
You must explicitly use delete.
class A {
public:

A() { Output:
cout << "Constructor A\n";
} Constructor A
Destructor A
~A() {
cout << "Destructor A\n";
} If delete p; is omitted, the destructor will
}; not be called, causing a memory leak.

int main() {

A* p = new A(); // Constructor called

delete p; // Destructor called explicitly

return 0;
}
Feature Constructor Destructor

Naming Same as class Same as class, prefixed with ~

Parameters Can have parameters Cannot have parameters

Return Type No return type No return type

Called when an object is Called when an object is


Call Time
created destroyed

Overloading Can be overloaded Cannot be overloaded

Should be virtual for Should be virtual if used in a


Inheritance
polymorphic behavior base class
class A {
public: int main() {
string n; A q; // Default constructor

A* q1 = new A("Q1"); // Dynamically allocated object


// Default Constructor A b("B"); // Local object with parameterized constructor
A() {
cout << "A Constructor H\n"; A* p; // Pointer (not initialized)
}
{ // Inner scope
// Parameterized Constructor A c("C"); // Local object with parameterized constructor
p = new A("P"); // Dynamically allocated object
A(string s) {
delete q1; // Explicitly deleting dynamically allocated
n = s; object
cout << "A Constructor " << n << } // 'c' goes out of scope here, so its destructor is called
"\n";
} A e("E"); // Another local object

// Destructor delete p; // Explicitly deleting dynamically allocated


object
~A() {
cout << "A Destructor " << n << "\n"; return 0;
} }
};
Code Execution Flow
1. A q;
▪ Calls the default constructor → Prints "A Constructor H"
2. A* q1 = new A("Q1");
▪ Dynamically allocates an object with "Q1"
▪ Calls the parameterized constructor → Prints "A Constructor Q1"
3. A b("B");
▪ Creates a local object "B"
▪ Calls the parameterized constructor → Prints "A Constructor B"
4. A* p;
▪ Creates a pointer to A, but does not allocate memory (so no constructor call)
5. Inner Scope {}
▪ A c("C");
▪ Creates a local object "C"
▪ Calls the parameterized constructor → Prints "A Constructor C"
▪ p = new A("P");
▪ Dynamically allocates an object "P"
▪ Calls the parameterized constructor → Prints "A Constructor P"
▪ delete q1;
▪ Deletes "Q1"
▪ Calls the destructor → Prints "A Destructor Q1"
▪ Inner scope ends
▪ "c" goes out of scope, so its destructor is called → Prints "A Destructor C"
6. A e("E");
▪ Creates a local object "E"
▪ Calls the parameterized constructor → Prints "A Constructor E"
7. delete p;
▪ Deletes "P"
▪ Calls the destructor → Prints "A Destructor P"
8. Function main() ends
▪ Local objects (b, e, q) go out of scope
▪ Destructors are called in reverse order of creation:
▪ "E" → "B" → "H" (default constructor object)
Output:

A Constructor H
A Constructor Q1
A Constructor B
A Constructor C
A Constructor P
A Destructor Q1
A Destructor C
A Constructor E
A Destructor P
A Destructor E
A Destructor B
A Destructor
▪ Objects created with new must be deleted using delete.

▪ Local (stack) objects are automatically destroyed when they go out of scope.

▪ If delete is missing for a new object, memory leaks occur.

▪ Default Constructor is called for q (since no argument is passed).

▪ Parameterized Constructor is used for "Q1", "B", "C", "P", and "E".

▪ Dynamically allocated objects (q1 and p) must be explicitly deleted using delete.

▪ Local objects (c, b, e, q) are automatically destroyed when they go out of scope.

▪ Objects are destroyed in reverse order of their creation (Last In, First Out - LIFO).
Difference Between Structure and Class in C++

Feature Structure (struct) Class (class)

Default Access Modifier Public Private

Used for complex data with


Usage Used for simple data grouping
encapsulation

Less strict (all members public More strict (data hiding by


Encapsulation
by default) default)

Inheritance Inherits publicly by default Inherits privately by default

Member Functions Allowed Allowed

Constructor & Destructor Supported Supported

Mostly for Plain Data Structures Used for Object-Oriented


Real-world Use
(like C structs) Programming (OOP)
struct MyStruct {

int x; // Public by default

};

class MyClass {

int x; // Private by default

};

▪ Use struct for simple data containers (like C-style structs).


▪ Use class for full-fledged objects with encapsulation.
Function Overloading and Constructor Overloading in C++

Function Overloading

Function overloading allows multiple functions to have the same name but different parameter lists
(different number or types of parameters).

Same function name but different parameter lists.

Can be overloaded by:


▪ Number of parameters
▪ Type of parameters

Return type cannot be used to differentiate functions


Function Overloading

int add(int a, int b) {


return a + b;
}

float add(float a, float b) {


return a + b;
}

char add(char a, char b) {


return a + b;
}

int main() {
cout << add(2, 3) << endl; // Calls int version
cout << add(2.5f, 3.2f) << endl; // Calls float version
cout << add('A', 'B') << endl; // Calls char version
return 0;
}
Constructor Overloading

Just like functions, constructors can also be overloaded with different parameter lists.

▪ Same constructor name but different parameter lists

▪ Used to provide multiple ways to initialize an object

▪ If no constructor is defined, a default constructor is automatically created

▪ If a constructor with parameters is defined but no default constructor exists, then objects cannot

be created without arguments


class Point { int main() {
int x, y; Point p1; // Calls default constructor
Point p2(5); // Calls constructor with one parameter
public: Point p3(4, 9); // Calls constructor with two parameters
Point() { // Default Constructor
x = 0; [Link]();
y = 0; [Link]();
}
[Link]();
Point(int a) { // Constructor with one parameter
x = a; return 0;
y = 0; }
}

Point(int a, int b) { // Constructor with two parameters


x = a;
y = b;
}

void display() {
cout << "(" << x << ", " << y << ")" << endl;
}
};
If a default constructor is missing, then creating an object without arguments will cause a
compilation error.

Example:
If we remove Default Constructor in previous program

Point() { // Default Constructor


x = 0;
y = 0;
}

Creating object will give error.

Point p; // Error if no default constructor exists


Constructor
Feature Function Overloading
Overloading

Provides multiple
implementations of a Provides multiple ways
Purpose
function with the same to initialize an object
name

By number or type of By number or type of


Differentiation
parameters parameters

Not applicable
Cannot be used to
Return Type (constructors have no
differentiate
return type)

Default constructor is
No function is automatically provided if
Default Handling
automatically created no constructor is
defined
Encapsulation in C++

Encapsulation is a fundamental principle of Object-Oriented Programming (OOP) that:

1. Restricts direct access to data members.


2. Exposes only necessary functionalities using methods.

Example: Mobile Phone

▪ Encapsulation hides complexity: A user only interacts with the main features (e.g., calling,
messaging) without seeing the internal circuits.

▪ Two principles:
▪ Restrict direct access to sensitive data.
▪ Provide necessary functionalities while hiding the implementation.
Access Specifiers

Specifier Accessibility

Public Accessible from anywhere.

Private Accessible only within the class.

Protected Accessible within the class and its derived classes.


Encapsulation using struct and class
▪ Issue in struct (Everything is Public by
Default)

struct Point {
int x; // Public by default
int y;
int main() {
// Constructor Point j; // Default constructor
Point(int a = 0, int b = 0) { j.x = -5; // Allowed (since struct members are public)
if (a >= 0 && b >= 0) { j.y = -10; // Allows negative values, leading to errors
x = a;
return 0;
y = b;
}
} else {
cout << "Invalid input!\n";
}
}
};

Problem:
▪ Since struct members are public by default, we can directly modify x and y, allowing incorrect values.
▪ Fixing the Issue with class (Encapsulation using Private Members)
class Point { // Setter Methods (with validation)
private: void setX(int a) {
int x; if (a >= 0) x = a;
int y; else cout << "Invalid X
value!\n";
public: }
// Constructor with validation
Point(int a = 0, int b = 0) { void setY(int b) {
if (a >= 0 && b >= 0) { if (b >= 0) y = b;
x = a; else cout << "Invalid Y
y = b; value!\n";
} else { }
cout << "Invalid input!\n"; };
x = 0;
int main() {
y = 0; Point j; // Default constructor
}
} // j.x = -5; // Error: x is private (Encapsulation working)
// Getter Methods [Link](-5); // Output: Invalid X value!
[Link](10); // Correct
int getX() { return x; }
int getY() { return y; }
cout << "X: " << [Link]();
cout<< ", Y: " << [Link]() << "\n";
return 0;
}
▪ Encapsulation prevents direct modification of data.
▪ class is private by default, ensuring safety.
▪ Getters and Setters allow controlled access to private data.
▪ Validation inside constructors prevents invalid object creation.
▪ If a constructor is private, you cannot create objects directly.
▪ Auxiliary functions (helper functions) assist the main program but are not exposed
externally.
▪ Structures vs. Classes:
▪ Structure (struct): Everything is public by default.
▪ Class (class): Everything is private by default.
▪ Encapsulation ensures data security by restricting direct access to class members.
▪ Private data members can only be accessed through public getters and setters.
▪ Constructors validate inputs, preventing invalid object states.
▪ Encapsulation supports abstraction, hiding implementation details.
#include <iostream> int main() {
#include <cmath> Point p1(3, 4);
using namespace std; Point p2(6, 8);

class Point { [Link]();


// Getter functions
private: [Link]();
int getX() { return x; }
int x;
int getY() { return y; }
int y; cout << "Distance between points: " << [Link](p2) << endl;

// Setter functions with validation


public: return 0;
void setX(const int a) {
// Constructor with input }
if (a >= 0) x = a;
validation
else cout << "Invalid X value!\n";
Point(int a = 0, int b = 0) {
}
if (a >= 0 && b >= 0) {
x = a;
void setY(const int b) {
y = b;
if (b >= 0) y = b;
} else {
else cout << "Invalid Y value!\n";
cout << "Invalid input!\n";
}
x = 0;
y = 0;
// Function to display coordinates
}
void display() {
}
cout << "(" << x << ", " << y << ")\n";
}

// Function to calculate distance from another point


double distance(const Point &p) {
return sqrt(pow(x - p.x, 2) + pow(y - p.y, 2));
}
};
Separating Class Definition (.h) and Implementation (.cpp)

▪ Header File (Point.h)

▪ Implementation File ([Link])

▪ Main File ([Link])


#ifndef POINT_H
1. Header File (Point.h)
#define POINT_H

#include <iostream>
#include <cmath>

class Point {
private:
int x;
int y;

public:
// Constructor
Point(int a = 0, int b = 0);

// Getter functions
int getX() const;
int getY() const;

// Setter functions
void setX(const int a);
void setY(const int b);

// Display function
void display() const;

// Function to calculate distance


double distance(const Point &p) const;
};

#endif // POINT_H
2. Implementation File ([Link])
#include "Point.h" // Getter function definitions
using namespace std; int Point::getX() const { return x; }
int Point::getY() const { return y; }
// Constructor definition
Point::Point(int a, int b) { // Setter function definitions
if (a >= 0 && b >= 0) { void Point::setX(const int a) {
x = a; if (a >= 0) x = a;
y = b; else cout << "Invalid X value!\n";
} else { }
cout << "Invalid input!\n";
x = 0; void Point::setY(const int b) {
y = 0; if (b >= 0) y = b;
} else cout << "Invalid Y value!\n";
} }

// Display function definition


void Point::display() const {
cout << "(" << x << ", " << y << ")\n";
}

// Distance function definition


double Point::distance(const Point &p) const {
return sqrt(pow(x - p.x, 2) + pow(y - p.y, 2));
}
3. Main File ([Link])

#include "Point.h"

int main() {
Point p1(3, 4);
Point p2(6, 8);

[Link]();
[Link]();

std::cout << "Distance between points: " << [Link](p2) << std::endl;

return 0;
}
Notes
Inline Functions in C++

▪ By default, all functions defined inside a class are inline.

▪ Advantages:

▪ Eliminates function call overhead.


▪ Helps in optimizing small, frequently used functions.

▪ Important Note: The compiler decides whether to inline a function; the inline keyword is a
suggestion.

class Point {
public:
inline void print() {
cout << "X: " << x << ", Y: " << y;
}
};
What are Inline Functions?
An inline function in C++ is a function for which the compiler replaces the function call
with the actual function code during compilation. This avoids the overhead of a function
call, improving performance for small, frequently used functions.
Why Use Inline Functions?
1. Function calls introduce overhead Pushing arguments onto the stack.
2. Jumping to the function definition and executing it.
3. Returning control back to the caller.
▪ due to:
▪ For small functions, this overhead can be more expensive than the function itself.
▪ Inlining eliminates this by inserting the function code directly at the call site.

Syntax of Inline Functions


To declare a function as inline, use the inline keyword before the function definition:
inline int add(int a, int b) {
return a + b;
}
When add(x, y) is called, the compiler replaces it with x + y, instead of performing a function call.
Example of an Inline Function
class Math {
public:
inline int square(int x) {
return x * x;
}
};

int main() {
Math obj;
cout << "Square of 5: " << [Link](5) << endl;
return 0;
}

How it Works?
▪ Instead of calling square(5), the compiler replaces it with 5 * 5 directly in main().
▪ This reduces execution time by eliminating function call overhead.
Inline Functions Inside a Class

▪ Functions defined inside a class are implicitly inline (even without the inline keyword).
▪ Example:
class Point {
public:
int x, y;
void show() { // Implicitly inline
cout << "X: " << x << ", Y: " << y << endl;
}
};

▪ The compiler automatically treats show() as an inline function.


When to Use Inline Functions?

Use inline for:


▪ Small, frequently used functions (1-3 lines).
▪ Getter functions that return private members.
▪ Operator overloading functions for simple operations.

Avoid inline for:


▪ Functions with loops, recursion, or complex logic.
▪ Functions that use static variables (as multiple copies may cause issues).
▪ Functions that are too large (increases code size, leading to slower execution).
Advantages of Inline Functions

▪ Reduces function call overhead (especially for small functions).


▪ Speeds up execution for simple functions.
▪ Improves performance when used correctly.

Disadvantages of Inline Functions

▪ Increases executable file size (code duplication).


▪ May lead to cache inefficiency if used excessively.
▪ Compiler ignores inline for complex functions (loops, recursion).
▪ The compiler decides whether to inline a function (even if marked inline).

▪ Functions defined inside a class are automatically inline.

▪ Large functions should not be inlined (increases code size, reducing efficiency).

▪ Inlining does not work with virtual functions, as their calls are resolved at runtime.
What is the (this Pointer)?

▪ The (this pointer) in C++ is an implicit pointer available inside non-static member
functions of a class. It points to the current object that invokes the function.

Properties of this Pointer

▪ It is an implicit pointer (automatically provided by the compiler).

▪ It stores the memory address of the calling object.

▪ It can be used to differentiate instance variables from parameters when they have the
same name.

▪ The (this pointer) is not available in static functions because they belong to the class,
not any specific object.
Understanding this Pointer
class Example {
private:
int x;

public:
void setX(int x) {
this->x = x; // Using 'this' to differentiate between instance variable and parameter
}

void display() {
cout << "Value of x: " << this->x << endl;
}
};

int main() {
Example obj;
[Link](10);
[Link]();

return 0;
Explanation
}
▪ setX(int x) has a local variable x that shadows the instance variable x.
▪ this->x refers to the instance variable, while x (without this) refers to the parameter.
▪ this ensures that we are assigning the parameter value to the instance variable.
Returning this Pointer
▪ The (this pointer) can be used to return the current object.
class Example {
private:
int x;

public:
Example& setX(int x) {
this->x = x;
return *this; // Returning the current object
}

void display() {
cout << "Value: " << x << endl;
}
};

int main() {
Example obj;
[Link](20).display(); // Chained function calls
return 0;
}
Explanation
▪ setX(int x) assigns a value and returns *this (the current object).
▪ This allows method chaining, where we call display() directly after setX(20).
(this Pointer) in Copy Constructor
▪ The (this pointer) is useful in copy constructors to avoid self-assignment issues.

class Example {
private:
int x;

public:
Example(int x) { this->x = x; }

Example(Example &obj) { // Copy constructor


this->x = obj.x;
}

void display() {
cout << "Value: " << x << endl;
}
};

int main() {
Example obj1(50);
Example obj2 = obj1; // Calls copy constructor

[Link]();
[Link]();

return 0; Explanation
} ▪ The copy constructor Example(Example &obj) assigns values using this->x = obj.x.
▪ This ensures the new object gets the same value as obj1.
(this Pointer)
▪ The (this pointer) points to the current instance of the class.
▪ It is automatically passed to all non-static member functions.

class Point {
int x, y;
public:
void setX(int x) {
this->x = x;
}
};

Advantages of this Pointer

▪ Helps differentiate instance variables from local variables.


▪ Enables method chaining by returning the current object.
▪ Prevents self-assignment in operator overloading.
▪ Used in copy constructors to assign values correctly.
const and static in C++
const in C++

▪ The const keyword is used to define constant values, functions, and objects that cannot be modified
after initialization.

const Variable

▪ A const variable is a read-only variable whose value cannot be changed after initialization.

Example: Declaring and Using const Variables

int main() {
const int x = 10; // Constant integer
cout << "x = " << x << endl;

// x = 20; // Error: assignment of read-only variable 'x'

return 0;
}

▪ const variables must be initialized when declared.


▪ They cannot be modified later.
▪ Used to prevent accidental modifications.
const Function

A const function in a class does not modify the object's state. It is mainly used in getter
functions.

Example: const Function in a Class


class Example {
private:
int x;

public:
Example(int val) { x = val; }

void setX(int val) { x = val; }

int getX() const { // `const` function


return x;
}
};
▪ const functions cannot modify any member variables.
▪ They are useful for getter methods.
▪ If you try modifying any member inside a const function, a compiler error occurs.
const Object

A const object is an instance of a class that cannot modify its own data.

Example: Declaring a const Object

class Example {
private:
int x;

public:
Example(int val) { x = val; }

int getX() const { return x; } // `const` function

void setX(int val) { x = val; } // Non-const function


};

int main() {
const Example obj(10); // `const` object

cout << [Link]() << endl; // Allowed (const function)

// [Link](20); // Error: Cannot call a non-const function on a const object

return 0; ▪ A const object can only call const functions.


} ▪ It cannot modify its own members.
▪ Useful for ensuring immutability in a program.
static in C++
The static keyword defines class-wide members that belong to the class itself rather than
any particular instance.

static Variable
A static variable inside a class is shared among all instances of that class.

Example: Using a static Variable


class Example {
private:
static int count; // Static variable ▪ static variables are shared across all instances of the class.
▪ They are declared inside the class but defined outside the class.
public: ▪ They retain their value between function calls.
Example() { count++; }

static int getCount() { return count; } // Static function


};

// Definition of static variable (outside class)


int Example::count = 0;

int main() {
Example obj1, obj2, obj3;
cout << "Total Objects: " << Example::getCount() << endl; // Output: 3

return 0;
}
static Function

A static function belongs to the class rather than any instance. It can only access static
members.

Example: Declaring and Using a static Function


class Example {
private:
static int count;

public:
static void showCount() { ▪ static functions do not require an object to be called.
cout << "Count: " << count << endl; ▪ They cannot access non-static members of the class.
}
};

// Definition of static variable


int Example::count = 10;

int main() {
Example::showCount(); // Calling a static function

return 0;
}
Static Objects in C++

A static object is an object that persists throughout the program's execution. It is initialized only
once and retains its value between function calls.

▪ Lifetime: A static object is created only once and destroyed at the end of the program.
▪ Scope: If declared inside a function, it remains local to the function but retains its value
between calls.
▪ Initialization: It is initialized only once when encountered for the first time.

Example 1: Static Object Inside a Function

void test() {
static Example obj; // Static object (created once)
[Link]();
}
class Example {
public:
Example() {
cout << "Constructor called" << endl;
} •The static object obj inside test() is created only once.
~Example() { •Even though test() is called multiple times, the object is not re-created.
cout << "Destructor called" << endl; •The destructor is called only when the program exits.
}

void display() {
cout << "Hello from Example class!" << endl;
}
};

void test() {
static Example obj; // Static object (created once)
Constructor called
[Link](); Hello from Example class!
} Hello from Example class!
Destructor called (after program exits)
int main() {
test(); // First call: Object is created and used
test(); // Second call: Same object is reused (no new constructor call)
return 0;
}
Member Initialization List in C++

A Member Initialization List in C++ is used to initialize class data members


before the constructor body executes. This is particularly useful for const
members, reference members, and base class initialization.

class ClassName {

int a;
const int b;

public:
// Constructor using Member Initialization List

ClassName(int x, int y) : a(x), b(y) {


cout << "Constructor called\n";
}
};
Why Use Member Initialization List?

▪ Efficient Initialization: Avoids an extra assignment.


▪ Mandatory for const and reference members: These cannot be assigned later.
▪ Base Class Initialization: Ensures correct construction order.
class A {
int x; class Example {
const int y; // Constant member const int a; // Constant member
int &ref; // Reference member
int &z; // Reference member
public:
public: int value = 50; // Normal member variable
// Constructor with Member Initialization List
A(int a, int b, int &c) : x(a), y(b), z(c) { // Member Initialization List with Default Values
Example() : a(100), ref(value) {
cout << "x: " << x << ", y: " << y << ", z: " << z << endl; cout << "a = " << a << ", ref = " << ref << endl;
} }
}; };

int main() { int main() {


Example obj; // Default constructor is called
int num = 30; return 0;
A obj(10, 20, num); }
return 0;
} •Initializing const and reference members.
•Optimized initialization for performance.
•Ensuring base classes are correctly initialized before derived class members.
Method Chaining in C++
Method Chaining in C++
▪ Method chaining is a programming technique where multiple function calls on the same object are linked
together in a single statement.

▪ This approach enhances code readability and reduces the need for intermediate variables.

▪ It is commonly used in scenarios such as configuring objects, performing sequential operations, and
implementing fluent APIs.
▪ A technique where multiple methods are called in a single statement.

▪ Each method returns a reference to the calling object (*this), enabling subsequent method calls.

Benefits of Method Chaining

▪ Improved Code Readability


▪ Eliminates redundant intermediate statements.
▪ Keeps related operations in a single line.
▪ Fluent Interface Design
▪ Makes APIs more intuitive, especially in object configuration and data manipulation.
▪ Reduced Code Complexity
▪ Avoids unnecessary temporary variables and extra function calls.
Example Use Case: String Formatter

[Link]().append(" World").show();

Without Method Chaining:

[Link]();
[Link](" World");
[Link]();

▪ Method chaining leads to cleaner, more expressive code.


class Student { int main() {
private:
string name; Student s("Ali");
string courses; // Stores course names as a single string
public: [Link]("Math").addCourse("Physics").showCourses()
Student(string studentName) : name(studentName), courses("") {} .addCourse("Computer Science").showCourses();

Student& addCourse(string course) { return 0;


if (![Link]()) { }
courses += ", "; // Add separator between courses
}
courses += course;
return *this;
}

Student& showCourses() {
cout << "Student: " << name << "\nCourses: " << ([Link]() ? "None" : courses) << endl;
return *this;
}
};

Chaining Usage:
Output:
[Link]("Math").addCourse("Physics").showCourses().addCourse("ComputerScience").showCourses(); Student: Ali
Courses: Math, Physics
Student: Ali
Returning *this from showCourses() doesn’t mean the result must be stored. It just allows Courses: Math, Physics, Computer Science
seamless chaining, making the code more concise
class Rectangle { int main() {
private: Rectangle r;
int width, height;
public: [Link](5).setHeight(10).showArea().setWidth(7).setHeight(3).showArea();
Rectangle() : width(0), height(0) {} return 0;
}
Rectangle& setWidth(int w) {
width = w;
return *this;
}

Rectangle& setHeight(int h) {
height = h;
return *this;
}

Rectangle& showArea() {
cout << "Area = " << (width * height) << endl;
return *this;
}
};

Returning *this from showArea() doesn’t mean the result Output:


must be stored. It just allows seamless chaining, making the Area = 50
code more concise Area = 21
class BankAccount { int main() {
private: BankAccount acc(100);
double balance; [Link](50).showBalance().withdraw(30).showBalance().withdraw(150).showBalance();
public: return 0;
BankAccount(double initial) : balance(initial) {} }

BankAccount& deposit(double amount) {


balance += amount;
return *this;
}

BankAccount& withdraw(double amount) {


if (amount <= balance) {
balance -= amount;
} else {
cout << "Insufficient funds!" << endl;
}
return *this;
}

BankAccount& showBalance() {
cout << "Balance: $" << balance << endl;
return *this; Output:
} Balance: $150
}; Returning *this from showBalance() doesn’t mean the result Balance: $120
must be stored. It just allows seamless chaining, making the Insufficient funds!
code more concise Balance: $120
class StringFormatter { int main() {
private: StringFormatter sf("Hello");
string text; [Link]().show().append(" World!").show().toLowerCase().show();
public:
return 0;
StringFormatter(string str) : text(str) {}
}
StringFormatter& toUpperCase() {
for (char &c : text) c = toupper(c);
return *this;
}

StringFormatter& toLowerCase() {
for (char &c : text) c = tolower(c);
return *this;
}

StringFormatter& append(string extra) {


text += extra;
return *this;
}

StringFormatter& show() {
cout << "Formatted String: " << text << endl; Output:
return *this; Formatted String: HELLO
} Returning *this from show() doesn’t mean the result must be Formatted String: HELLO World!
}; stored. It just allows seamless chaining, making the code Formatted String: hello world!
more concise
class FileWriter {
private:
ofstream file;
public:
FileWriter(string filename) { int main() {
[Link](filename); FileWriter fw("[Link]");
} [Link]("Hello, World!").write("This is C++ chaining
example.").close();
FileWriter& write(string text) { return 0;
if (file.is_open()) { }
file << text << endl;
}
return *this;
}

FileWriter& close() {
if (file.is_open()) {
[Link]();
}
return *this;
}
};
class Rectangle {
private: int main() {
double length, width; Rectangle r;
public: [Link](10).setWidth(5).showArea();
Rectangle() : length(0), width(0) {} return 0;
}
Rectangle& setLength(double l) {
length = l;
return *this;
}

Rectangle& setWidth(double w) {
width = w;
return *this;
}

Rectangle& showArea() {
cout << "Area: " << length * width << endl;
return *this;
}
};
class Query {
private: int main() {
string query; Query q;
public: [Link]("age > 18").orderBy("name").execute();
Query() : query("SELECT * FROM students") {} return 0;
}
Query& where(string condition) {
query += " WHERE " + condition;
return *this;
}

Query& orderBy(string column) {


query += " ORDER BY " + column;
return *this;
}

Query& execute() {
cout << "Executing: " << query << endl;
return *this;
}
};

You might also like