📘 Lecture 34
🔹 1) Arrays of Objects
📖 Definition:
An array of objects means creating multiple objects of a class using an array, just like an array
of integers or strings.
It helps you store and manage many objects of the same class together.
✅ Example:
#include <iostream>
using namespace std;
class Student {
public:
void show() {
cout << "I am a student" << endl;
}
};
int main() {
Student s[3]; // Create an array of 3 Student objects
// Call the show() function for each student
s[0].show();
s[1].show();
s[2].show();
return 0;
}
💬 Explanation:
• We made a class Student.
• Then created 3 students using an array: Student s[3];
• Each student can call functions independently.
🔹 2) Dynamic Arrays of Objects
📖 Definition:
Dynamic arrays are created at runtime using new. You can decide the number of objects while
the program is running, not before.
✅ Example:
#include <iostream>
using namespace std;
class Student {
public:
void show() {
cout << "Dynamic student" << endl;
}
};
int main() {
Student* s = new Student[2]; // Creates 2 Student objects dynamically
s[0].show(); // Call show() for first object
s[1].show(); // Call show() for second object
delete[] s; // Always free the memory after use
return 0;
}
💬 Explanation:
• We used new to create a dynamic array of Student.
• Used delete[] to clean the memory.
🔹 3) Overloading new and delete Operators
📖 Definition:
You can customize how memory is allocated and deallocated for objects by overloading the
new and delete operators inside a class.
✅ Example:
#include <iostream>
#include <cstdlib> // for malloc and free
using namespace std;
class MyClass {
public:
// Overload new operator
void* operator new(size_t size) {
cout << "Custom new operator called" << endl;
return malloc(size); // Allocate memory manually
}
// Overload delete operator
void operator delete(void* ptr) {
cout << "Custom delete operator called" << endl;
free(ptr); // Free memory manually
}
};
int main() {
MyClass* obj = new MyClass(); // Calls custom new
delete obj; // Calls custom delete
return 0;
}
💬 Explanation:
• newand delete are redefined.
• Now, whenever we create or delete an object, our custom message and logic is used.
🔹 4) Example of Overloading new and delete as Non-members
📖 Definition:
We can also overload new and delete globally (outside the class) to apply to all objects in the
program.
✅ Example:
#include <iostream>
#include <cstdlib>
using namespace std;
// Global overload of new
void* operator new(size_t size) {
cout << "Global new called" << endl;
return malloc(size);
}
// Global overload of delete
void operator delete(void* ptr) noexcept {
cout << "Global delete called" << endl;
free(ptr);
}
class MyClass {
int x;
};
int main() {
MyClass* obj = new MyClass; // Will call global new
delete obj; // Will call global delete
return 0;
}
💬 Explanation:
• This applies new and delete to all classes, unless class-specific ones are defined.
🔹 5) Overloading new and delete as Members
📖 Definition:
This means writing new and delete inside a specific class to control memory only for that
class.
✅ Already shown above in point 3.
💬 Explanation:
• These are useful when a class needs special memory handling (e.g., logging or debugging
memory usage).
🔹 6) Overloading [] Operator to Create Arrays
📖 Definition:
You can overload the [] operator so you can use array-like indexing on your custom object.
✅ Example:
#include <iostream>
using namespace std;
class Marks {
int arr[5]; // internal array
public:
Marks() {
for (int i = 0; i < 5; i++) {
arr[i] = i * 10; // Fill array with values 0, 10, 20, 30, 40
}
}
// Overload [] operator
int operator[](int index) {
return arr[index]; // Return value at given index
}
};
int main() {
Marks m;
cout << "Value at index 2: " << m[2] << endl; // Output: 20
return 0;
}
💬 Explanation:
• We created a class with an array.
• Used operator[] so we can write m[2] like a normal array.
📗 Lecture 35 — Input/Output Streams
🔹 1) Streams
📖 Definition:
A stream is a path through which data flows. In C++, data can flow:
• Into a program from the keyboard (input stream like cin)
• Out of a program to the screen (output stream like cout)
✅ Example:
#include <iostream>
using namespace std;
int main() {
int age;
// Ask the user to enter age
cout << "Enter your age: "; // Output stream (cout)
cin >> age; // Input stream (cin) gets value from keyboard
cout << "Your age is: " << age << endl; // Display the value
return 0;
}
💬 Explanation in comments:
• cout is used to display output (to screen)
• cin is used to take input (from keyboard)
• These are examples of streams
🔹 2) Source and Destination of Streams
📖 Definition:
In a stream:
• Source is where data comes from (e.g., keyboard)
• Destination is where data goes to (e.g., screen)
✅ Example:
#include <iostream>
using namespace std;
int main() {
int number;
// Keyboard (source) → number (destination)
cout << "Enter a number: ";
cin >> number;
// number (source) → Screen (destination)
cout << "You entered: " << number << endl;
return 0;
}
💬 Explanation:
• When using cin, source = keyboard, destination = variable
• When using cout, source = variable, destination = screen
🔹 3) Formatted Input and Output
📖 Definition:
Formatted I/O means controlling how data is shown, e.g., using width, precision, alignment,
etc., using iomanip library.
✅ Example:
#include <iostream>
#include <iomanip> // for formatting
using namespace std;
int main() {
float pi = 3.14159;
// Set width and precision for output
cout << "Value of pi with 2 decimal places: " << fixed << setprecision(2)
<< pi << endl;
// setw(10) sets field width to 10 spaces
cout << setw(10) << 42 << endl;
return 0;
}
💬 Explanation:
• setprecision(2) sets 2 digits after decimal
• setw(10) reserves 10 spaces to print value
🔹 4) Recap Streams
📖 Definition:
Streams are used for:
• Reading input (cin)
• Writing output (cout)
• Reading from files (ifstream)
• Writing to files (ofstream)
They make input/output easier and more flexible.
✅ Quick Recap Code:
#include <iostream>
#include <fstream> // for file streams
using namespace std;
int main() {
ofstream file("data.txt"); // Output stream to file
file << "Hello File"; // Write to file
file.close();
return 0;
}
💬 Explanation:
• ofstream is an output file stream (writes to a file).
• C++ streams are not just for screen/keyboard — they work with files too.
🔹 5) Buffered Input/Output
📖 Definition:
Buffered I/O stores input/output in a temporary memory area (buffer). It sends/receives data
in chunks for better performance.
✅ Example:
#include <iostream>
using namespace std;
int main() {
cout << "This is buffered output";
// Buffer is flushed (output sent to screen) only when endl or flush is
used
cout << endl; // flushes the buffer
return 0;
}
💬 Explanation:
• endlflushes (empties) the buffer and sends output to screen.
• Without flushing, output may stay in memory for a moment.
🔹 6) Methods with Streams
📖 Definition:
Streams have built-in methods like:
• .get() – reads a character
• .put() – writes a character
• .ignore() – skips input
• .eof() – checks end of file
✅ Example:
#include <iostream>
using namespace std;
int main() {
char ch;
cout << "Enter any character: ";
cin.get(ch); // gets a single character including whitespace
cout.put(ch); // prints the character
return 0;
}
💬 Explanation:
• get() is used to take a single character (including spaces)
• put() is used to output a single character
🔹 7) Examples Using Streams
📖 Definition:
You can use streams for both file and keyboard/screen I/O.
✅ Example: Read and write file
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ofstream outFile("test.txt"); // Create file and open for writing
outFile << "Learning C++ Streams"; // Write to file
outFile.close(); // Close file
string content;
ifstream inFile("test.txt"); // Open same file for reading
getline(inFile, content); // Read line from file
cout << "File says: " << content << endl;
inFile.close();
return 0;
}
💬 Explanation:
• ofstream writes to file
• ifstream reads from file
• getline() reads a full line from file
✅ Summary Table
Topic What it Means
Streams Flow of input/output data
Source & Destination Where data comes from/goes to
Formatted I/O Control how data is displayed
Buffered I/O Temp memory used for faster I/O
Stream Methods Functions like get(), put(), eof()
Using Streams Input/output from screen and files
✅ Lecture 36
37) Stream Manipulations
These are ways to control how data is input/output in C++.
They help format numbers, text, and align content in the console output.
38) Manipulators
Special functions in C++ used to format output like setting width, precision, etc.
Examples: setw(), setprecision(), endl, etc.
39) Non-Parameterized Manipulators
These manipulators don't take any values.
Example: endl is used to insert a newline.
#include <iostream>
using namespace std;
int main() {
cout << "Hello" << endl; // ends line
cout << "World";
return 0;
}
40) Parameterized Manipulators
They take arguments to modify the output format.
Used with iomanip header.
#include <iostream>
#include <iomanip> // for setw and setprecision
using namespace std;
int main() {
cout << setw(10) << 123 << endl; // width = 10
cout << setprecision(4) << 3.14159; // 4 total digits
return 0;
}
41) Format State Flags
Flags used to set output behavior like base, sign, alignment, etc.
Example: cout.setf(ios::showpos) shows + sign for positive numbers.
42) Formatting Manipulation
Combining manipulators and flags to control formatting of output.
For example, controlling left/right alignment or showing decimal points.
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
cout.setf(ios::left); // left align
cout << setw(10) << "Name" << "Age\n";
cout << setw(10) << "Ali" << 20;
return 0;
}
43) Showing the Base
Use manipulators to show the base of numbers like hexadecimal or octal.
#include <iostream>
using namespace std;
int main() {
int x = 255;
cout << showbase; // show base
cout << hex << x << endl; // hexadecimal with base
cout << oct << x << endl; // octal with base
return 0;
}
44) Scientific Representation
Used to show floating point numbers in scientific (exponential) form.
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
double num = 123456.789;
cout << scientific << num; // scientific format
return 0;
}
45) Exercise
Try this:
• Print a float in scientific form
• Print a number in hex with base
• Align three names in left and right alignment using setw()
✅ Lecture 37
Overloading Insertion and Extraction Operators
We can customize how objects are printed or read using << and >>.
#include <iostream>
using namespace std;
class Student {
int roll;
public:
Student(int r) { roll = r; }
// Overload <<
friend ostream& operator<<(ostream& out, Student s) {
out << "Roll No: " << s.roll;
return out;
}
};
int main() {
Student s1(101);
cout << s1; // Will call the overloaded << function
return 0;
}
✅ Lecture 38
46) User Defined Manipulator
You can create your own manipulator like endl for custom output formatting.
#include <iostream>
using namespace std;
// User-defined manipulator
ostream& myEndl(ostream& out) {
out << "\n----------\n";
return out;
}
int main() {
cout << "Hello" << myEndl << "World";
return 0;
}
47) Examples of User Defined Manipulator
You can define multiple manipulators for custom spacing, headers, etc.
ostream& showStars(ostream& out) {
out << "\n*****\n";
return out;
}
48) Static Keyword
static keeps a variable's value even after the function ends.
It's also used for class-level variables shared among all objects.
#include <iostream>
using namespace std;
void test() {
static int count = 0;
count++;
cout << count << endl;
}
int main() {
test(); test(); test(); // Output: 1 2 3
return 0;
}
49) Static Objects
Static objects are created only once, and destroyed at the end of the program.
class Demo {
public:
Demo() { cout << "Constructor\n"; }
~Demo() { cout << "Destructor\n"; }
};
int main() {
static Demo obj; // lives till end of program
}
50) Static Data Members of a Class
A static data member is shared by all objects of the class.
#include <iostream>
using namespace std;
class Student {
public:
static int count;
Student() { count++; }
};
int Student::count = 0;
int main() {
Student s1, s2;
cout << "Total Students: " << Student::count;
return 0;
}
✅ Lecture 39
✅ 51) Pointers
A pointer is a variable that stores the memory address of another variable.
int a = 10;
int* ptr = &a; // ptr stores the address of a
cout << *ptr; // prints the value of a using pointer
✅ 52) References
A reference is just another name (alias) for an existing variable. It must be initialized when
declared.
int a = 5;
int& ref = a; // ref is another name for a
ref = 10; // a is now 10
✅ 53) Call by Value
When using call by value, a copy of the variable is passed, so the original value doesn’t change.
void func(int x) {
x = 20;
}
int main() {
int a = 10;
func(a);
cout << a; // Output: 10 (original unchanged)
}
✅ 54) Call by Reference
In call by reference, the original variable is passed, so changes are reflected.
void func(int &x) {
x = 20;
}
int main() {
int a = 10;
func(a);
cout << a; // Output: 20
}
✅ 55) Dynamic Memory Allocation
We use new and delete to create and free memory at runtime.
int* p = new int; // dynamically allocate memory
*p = 50;
cout << *p; // Output: 50
delete p; // free memory
✅ 56) Assignment and Initialization
Initialization happens when you declare and assign a value.
Assignment happens after the variable is already created.
int a = 5; // Initialization
a = 10; // Assignment
✅ 57) Copy Constructor
A special constructor that is called when a new object is created from an existing object.
class Test {
public:
int x;
Test(int a) { x = a; }
Test(const Test &t) { x = t.x; } // Copy constructor
};
✅ 58) Example (Copy Constructor)
class Test {
public:
int x;
Test(int a) { x = a; }
Test(const Test &obj) { x = obj.x; }
};
int main() {
Test t1(10);
Test t2 = t1; // Copy constructor called
cout << t2.x; // Output: 10
}
✅ 59) Rules for Using Dynamic Memory Allocation
1. Always delete memory allocated using new.
2. Avoid memory leaks by freeing memory.
3. Initialize pointers to nullptr.
✅ 60) Usage of Copy Constructor
Used:
• When an object is passed by value to a function.
• When an object is returned from a function.
• When one object is used to initialize another.
✅ 61) Summary
• Pointer: Stores address.
• Reference: Alias.
• Call by Value: Original not affected.
• Call by Reference: Original changes.
• Dynamic Allocation: Uses new/delete.
• Copy Constructor: Copies object values safely.
✅ Lecture 40
This lecture focuses on object composition, where objects of one class are used inside another
class. It's a core part of Object-Oriented Programming (OOP) and helps create complex
structures from simpler parts.
✅ Objects as Class Members
When you create an object of one class inside another class, it is called an object as a class
member (also called composition).
✅ Why use it?
To reuse code and build complex structures by combining simpler objects.
✅ Example 1: Object as a Member
class Address {
public:
string city;
int zip;
void setAddress(string c, int z) {
city = c;
zip = z;
}
void display() {
cout << "City: " << city << ", ZIP: " << zip << endl;
}
};
class Student {
public:
string name;
Address addr; // Object of Address inside Student
void setStudent(string n, string c, int z) {
name = n;
addr.setAddress(c, z); // Using Address class functions
}
void display() {
cout << "Name: " << name << endl;
addr.display();
}
};
int main() {
Student s1;
s1.setStudent("Ali", "Lahore", 54000);
s1.display();
}
✅ Example 2: Nested Object with Constructor
class Date {
public:
int day, month, year;
Date(int d, int m, int y) {
day = d; month = m; year = y;
}
};
class Person {
public:
string name;
Date birthDate; // Composition
// Constructor initialization list used for object inside class
Person(string n, Date d) : name(n), birthDate(d) {}
void display() {
cout << "Name: " << name << ", DOB: "
<< birthDate.day << "/" << birthDate.month << "/" <<
birthDate.year << endl;
}
};
int main() {
Date d(10, 7, 2000);
Person p("Sara", d);
p.display();
}
✅ Advantages of Objects as Class Members
1. Code Reusability – Use existing class objects.
2. Modular Code – Break into smaller, manageable parts.
3. Clean Design – Logical relationships are easier to model (e.g., a Student has an
Address).
✅ Structures as Class Members
struct Result {
float marks;
string grade;
};
class Student {
public:
string name;
Result res; // Structure as member
void setData(string n, float m, string g) {
name = n;
res.marks = m;
res.grade = g;
}
void display() {
cout << "Name: " << name << ", Marks: " << res.marks << ", Grade: "
<< res.grade << endl;
}
};
✅ Classes inside Classes (Nested Classes)
You can define a class inside another class. This is called a nested class.
class Outer {
public:
class Inner {
public:
void show() {
cout << "Inside Inner class" << endl;
}
};
};
int main() {
Outer::Inner obj;
obj.show();
}
✅ Tips
• When using objects as members, constructors of those objects are called automatically.
• Use initialization lists in constructors when member objects don’t have default
constructors.
• Nested classes are useful for tightly coupling small helper classes.