C++ Notes
C++ Notes
1. Introduction
In C++, objects are instances of a class.
A class is a user-defined data type that can group multiple variables (called data members)
and functions (called member functions) into a single unit.
So, an object acts as a collection of related variables (attributes) that describe a real-world
entity.
For example:
3. Syntax
class ClassName {
public:
// variables (data members)
dataType var1;
dataType var2;
// ...
};
int main() {
ClassName obj; // creating an object
obj.var1 = value;
obj.var2 = value;
}
Here, obj groups together var1, var2, etc. as its own set of variables.
class Student {
public:
int rollNo; // data members (variables)
string name;
float marks;
};
int main() {
Student s1; // object 1
[Link] = 101;
[Link] = "Loki";
[Link] = 92.5;
cout << "Student 1: " << [Link] << ", " << [Link] << ", " << [Link]
<< endl;
cout << "Student 2: " << [Link] << ", " << [Link] << ", " << [Link]
<< endl;
return 0;
}
Explanation:
class Employee {
public:
int id;
string name;
double salary;
};
int main() {
Employee e1, e2;
// Displaying data
cout << "Employee 1 -> ID: " << [Link] << ", Name: " << [Link] << ",
Salary: " << [Link] << endl;
cout << "Employee 2 -> ID: " << [Link] << ", Name: " << [Link] << ",
Salary: " << [Link] << endl;
return 0;
}
Here, each object is a separate group of variables (like separate records in a database).
class Book {
public:
int bookID;
string title;
float price;
};
int main() {
Book books[3]; // array of objects
books[0].bookID = 1;
books[0].title = "C++ Basics";
books[0].price = 299.50;
books[1].bookID = 2;
books[1].title = "OOP Concepts";
books[1].price = 450.75;
books[2].bookID = 3;
books[2].title = "Data Structures";
books[2].price = 500.00;
// Displaying details
for (int i = 0; i < 3; i++) {
cout << "Book " << i+1 << ": "
<< books[i].bookID << ", "
<< books[i].title << ", "
<< books[i].price << endl;
}
return 0;
}
An array of objects groups many sets of variables into a single structure (like a library database
of books).
Thus, a class is a named group that combines variables and functions into a single unit.
3. Syntax of a Class
class ClassName {
public:
// data members
dataType variable1;
dataType variable2;
class Student {
public:
// data members
int rollNo;
string name;
float marks;
// member function
void displayDetails() {
cout << "Roll No: " << rollNo
<< ", Name: " << name
<< ", Marks: " << marks << endl;
}
};
int main() {
Student s1; // create object
[Link] = 101;
[Link] = "Loki";
[Link] = 95.5;
return 0;
}
Explanation:
class Car {
public:
string brand;
int speed;
void accelerate() {
speed += 10;
cout << brand << " accelerated. Speed = " << speed << endl;
}
void brake() {
speed -= 10;
cout << brand << " slowed down. Speed = " << speed << endl;
}
};
int main() {
Car c1;
[Link] = "Tesla";
[Link] = 50;
return 0;
}
Here, data members (brand, speed) represent the state of the car,
and methods (accelerate(), brake()) define its behavior.
class Employee {
public:
int id;
string name;
double salary;
void showInfo() {
cout << "ID: " << id
<< ", Name: " << name
<< ", Salary: " << salary << endl;
}
};
int main() {
Employee e1(1, "Ananya", 50000);
Employee e2(2, "Rahul", 60000);
[Link]();
[Link]();
return 0;
}
Constructors are special methods used to initialize data when objects are created.
struct Student {
int rollNo;
char name[20];
float marks;
};
int main() {
struct Student s1;
[Link] = 101;
strcpy([Link], "Loki");
[Link] = 92.5;
Here, Student groups data but cannot have functions like display() inside.
#include <iostream>
using namespace std;
struct Student {
int rollNo;
string name;
float marks;
// method inside structure
void display() {
cout << "Roll: " << rollNo << ", Name: " << name
<< ", Marks: " << marks << endl;
}
};
int main() {
Student s1 = {101, "Loki", 92.5};
[Link]();
return 0;
}
Notice: In C++, structures can also hold methods, making them closer to classes.
#include <iostream>
using namespace std;
class Student {
private:
int rollNo;
string name;
float marks;
public:
// constructor
Student(int r, string n, float m) {
rollNo = r;
name = n;
marks = m;
}
void display() {
cout << "Roll: " << rollNo
<< ", Name: " << name
<< ", Marks: " << marks << endl;
}
};
int main() {
Student s1(101, "Loki", 92.5);
[Link]();
return 0;
}
Classes take the idea of grouping data (like structs) and extend it with OOP features.
void display() {
cout << id << " " << name << " " << salary << endl;
}
};
public:
Employee(int i, string n, float s) {
id = i;
name = n;
salary = s;
}
void display() {
cout << id << " " << name << " " << salary << endl;
}
};
Summary:
int main() {
cout << "Hello, World!" << endl;
cout << "C++ Output Example" << endl;
return 0;
}
int main() {
int age;
cout << "Enter your age: ";
cin >> age; // input from user
cout << "You entered age = " << age << endl;
return 0;
}
cin automatically skips whitespace (spaces, tabs, newlines) when reading numbers or single
words.
int main() {
int a, b;
cout << "Enter two numbers: ";
cin >> a >> b; // input two integers
cout << "Sum = " << a + b << endl;
return 0;
}
return 0;
}
int main() {
double pi = 3.1415926535;
return 0;
}
Common manipulators:
Example 6:
#include <iostream>
using namespace std;
int main() {
cerr << "This is an error message!" << endl;
clog << "This is a log message!" << endl;
return 0;
}
9. Summary
cin → input using >>.
cout → output using <<.
cerr → immediate error messages.
clog → buffered error/log messages.
getline() → reads full string including spaces.
<iomanip> → formatting output.
Access Specifiers in C++
1. Introduction
In C++, access specifiers are keywords used to define the visibility (scope) of data members
(variables) and member functions (methods) inside a class.
3. Syntax
class ClassName {
private:
// private members
public:
// public members
protected:
// protected members
};
By default:
class Student {
public:
int rollNo; // public data
string name;
int main() {
Student s1;
[Link] = 101; // direct access (allowed)
[Link] = "Loki";
[Link](); // allowed
return 0;
}
class BankAccount {
private:
int accountNumber; // private data
double balance;
public:
void setAccount(int acc, double bal) {
accountNumber = acc;
balance = bal;
}
void showAccount() {
cout << "Account: " << accountNumber << ", Balance: " << balance <<
endl;
}
};
int main() {
BankAccount acc1;
// [Link] = 123; ❌ Error: private member
[Link](123, 5000); // Access through method
[Link]();
return 0;
}
Private members cannot be accessed directly → must use public methods (getter/setter).
This enforces data hiding.
class Person {
protected:
string name; // protected member
public:
void setName(string n) {
name = n;
}
};
int main() {
Student s1;
[Link]("Loki");
[Link]();
// cout << [Link]; ❌ Error: protected (not accessible outside)
return 0;
}
Protected members are not public, but they are accessible in derived classes.
7. Access Specifiers in Inheritance
When a class is inherited, the access specifiers affect how base class members are accessible in
the derived class.
8. Real-Life Analogy
Think of a Company Employee Record:
9. Quick Diagram
+---------------------+
| Class |
+---------------------+
Public | visible everywhere |
Private| visible only inside |
Protected | visible in class & children |
+---------------------+
10. Summary
public → Accessible everywhere.
private → Accessible only inside class.
protected → Accessible in class & subclasses.
Default:
o Class → private.
o Struct → public.
Member Functions in C++
1. Introduction
In C++, a member function is a function that is defined inside a class and operates on
the class’s data members.
Member functions represent the behavior (actions) of objects.
They are tightly bound to the class and can access private, protected, and public data
members.
2. Syntax
Inside the Class (Inline Definition)
class ClassName {
public:
void functionName() {
// code
}
};
class Student {
public:
int rollNo;
string name;
int main() {
Student s1;
[Link] = 101;
[Link] = "Loki";
[Link](); // calling member function
return 0;
}
class Student {
public:
int rollNo;
string name;
// definition outside
void Student::display() {
cout << "Roll: " << rollNo << ", Name: " << name << endl;
}
int main() {
Student s1;
[Link] = 102;
[Link] = "Ravi";
[Link]();
return 0;
}
Using scope resolution operator :: tells the compiler that the function belongs to the class.
5. Types of Member Functions
(a) Simple Member Functions
Functions defined inside class are treated as inline (compiler may replace the function call with
function body).
Reduces function call overhead for small functions.
class Employee {
private:
int salary;
public:
void setSalary(int s) { salary = s; }
int getSalary() { return salary; } // accessor
};
class Counter {
private:
static int count;
public:
Counter() { count++; }
static int getCount() { return count; }
};
int Counter::count = 0;
(f) Const Member Functions
class Student {
private:
string name;
public:
Student(string n) : name(n) {}
void display() const { // const function
cout << "Name: " << name << endl;
}
};
class BankAccount {
private:
int accountNo;
double balance;
public:
void setAccount(int acc, double bal) {
accountNo = acc;
balance = bal;
}
int main() {
BankAccount b1;
[Link](123, 1000);
[Link](500);
cout << "Balance: " << [Link]() << endl;
return 0;
}
7. Key Points
Member functions define behavior of objects.
Can be defined inside or outside the class.
Access private/protected data directly.
Types include: inline, static, const, getter, setter.
Accessed using dot operator (.) with object.
8. Real-Life Analogy
Think of a Car class:
Summary
Example
#include <iostream>
using namespace std;
class Student {
private:
int rollNo;
float marks;
public:
Student(int r, float m) {
rollNo = r;
marks = m;
}
// Accessor functions
int getRollNo() const { return rollNo; }
float getMarks() const { return marks; }
};
int main() {
Student s1(101, 95.5);
cout << "Roll: " << [Link]() << ", Marks: " << [Link]() <<
endl;
return 0;
}
Here getRollNo() and getMarks() are accessors.
Example
#include <iostream>
using namespace std;
class BankAccount {
private:
int accountNo;
double balance;
public:
void setAccount(int acc) { accountNo = acc; }
int main() {
BankAccount b1;
[Link](123);
[Link](5000); // mutator
cout << "Balance = " << [Link]() << endl;
return 0;
}
4. Auxiliary Functions
Purpose: Perform additional operations using the class data, but not strictly just get/set.
They often process, calculate, or display data.
Sometimes called helper functions.
Example
#include <iostream>
using namespace std;
class Rectangle {
private:
int length, width;
public:
Rectangle(int l, int w) {
length = l;
width = w;
}
// Accessor
int getLength() const { return length; }
// Mutator
void setWidth(int w) { width = w; }
// Auxiliary function
int area() const { return length * width; }
void display() const {
cout << "Length = " << length << ", Width = " << width
<< ", Area = " << area() << endl;
}
};
int main() {
Rectangle r1(10, 5);
[Link](); // auxiliary
[Link](8); // mutator
cout << "New Area = " << [Link]() << endl; // auxiliary
return 0;
}
area() and display() are auxiliary functions because they process/represent data rather
than just read/write it.
5. Summary Table
Function
Purpose Example
Type
Accessor Read/return private data (no modification). getMarks()
Mutator Modify/update private data (with validation). setBalance()
Perform additional tasks like compute, display, or process area(),
Auxiliary
data. display()
6. Real-Life Analogy
Consider a Bank ATM Machine:
Final Takeaway
2. Constructor
Definition
Rules
class Student {
private:
int rollNo;
string name;
public:
// Default constructor
Student() {
rollNo = 0;
name = "Unknown";
cout << "Default Constructor called" << endl;
}
void display() {
cout << "Roll: " << rollNo << ", Name: " << name << endl;
}
};
int main() {
Student s1; // constructor called automatically
[Link]();
return 0;
}
class Student {
private:
int rollNo;
string name;
public:
// Parameterized constructor
Student(int r, string n) {
rollNo = r;
name = n;
cout << "Parameterized Constructor called" << endl;
}
void display() {
cout << "Roll: " << rollNo << ", Name: " << name << endl;
}
};
int main() {
Student s1(101, "Loki"); // constructor with arguments
Student s2(102, "Ravi");
[Link]();
[Link]();
return 0;
}
public:
Rectangle() { // default
length = 0; width = 0;
}
void display() {
cout << "Length = " << length << ", Width = " << width << endl;
}
};
int main() {
Rectangle r1; // default
Rectangle r2(10,5); // parameterized
Rectangle r3(7); // overloaded
[Link]();
[Link]();
[Link]();
return 0;
}
3. Destructor
Definition
Rules
class Student {
private:
int rollNo;
public:
Student(int r) {
rollNo = r;
cout << "Constructor called for Roll " << rollNo << endl;
}
~Student() { // destructor
cout << "Destructor called for Roll " << rollNo << endl;
}
};
int main() {
Student s1(101);
Student s2(102);
cout << "Inside main function" << endl;
return 0;
} // destructors called automatically here
Output Order:
4. Key Differences
Feature Constructor Destructor
Purpose Initialize object Destroy object / free resources
Name Same as class ~ClassName
Return type None None
Arguments Allowed (overloading possible) Not allowed
Count per class Multiple (overloading) Only one
Called when Object is created Object goes out of scope
5. Real-Life Analogy
Constructor → Opening a file. (setup stage)
Destructor → Closing the file. (cleanup stage)
6. Special Types
Copy Constructor → Creates a new object as a copy of another object.
Dynamic Memory Cleanup → Destructor is used with new/delete for memory
management.
Final Takeaway
2. new Operator
Purpose: Allocates memory at runtime (on heap) for variables or objects.
Returns a pointer to the allocated memory.
Syntax:
int main() {
int *p = new int; // allocate memory for one integer
*p = 50; // assign value
cout << "Value: " << *p << endl;
delete p; // free memory
return 0;
}
int main() {
int *arr = new int[5]; // allocate array of 5 integers
// store values
for (int i = 0; i < 5; i++) {
arr[i] = (i + 1) * 10;
}
// display values
for (int i = 0; i < 5; i++) {
cout << arr[i] << " ";
}
cout << endl;
3. delete Operator
Purpose: Deallocates memory that was allocated with new.
Prevents memory leaks (unused memory that is never freed).
Syntax:
class Student {
public:
Student() { cout << "Constructor called" << endl; }
~Student() { cout << "Destructor called" << endl; }
void display() { cout << "Hello Student!" << endl; }
};
int main() {
Student *s = new Student; // constructor called
s->display();
delete s; // destructor called
return 0;
}
Example 4: Creating Array of Objects
#include <iostream>
using namespace std;
class Student {
public:
Student() { cout << "Constructor called" << endl; }
~Student() { cout << "Destructor called" << endl; }
};
int main() {
Student *arr = new Student[3]; // 3 objects created
delete[] arr; // destructors called for all
return 0;
}
6. Real-Life Analogy
new → Like booking a hotel room (you get space + setup).
delete → Like checking out of the room (releasing space).
7. Key Points
Always pair new with delete and new[] with delete[].
Failing to use delete causes memory leaks.
Using delete on already deleted memory = undefined behavior.
Final Takeaway
1. Function Overloading
2. Operator Overloading
2. Function Overloading
Definition
Function overloading means multiple functions with the same name but different parameter
lists (number or type).
Rules
class Math {
public:
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
int main() {
Math m;
cout << "Sum (int): " << [Link](10, 20) << endl;
cout << "Sum (double): " << [Link](2.5, 3.7) << endl;
cout << "Sum (3 int): " << [Link](5, 10, 15) << endl;
return 0;
}
3. Operator Overloading
Definition
C++ allows us to redefine operators (like +, -, ==) for user-defined types (classes/objects).
This is called operator overloading.
Rules
class Complex {
private:
int real, imag;
public:
Complex(int r = 0, int i = 0) {
real = r;
imag = i;
}
// Operator overloading
Complex operator+(const Complex& c) {
return Complex(real + [Link], imag + [Link]);
}
void display() {
cout << real << " + " << imag << "i" << endl;
}
};
int main() {
Complex c1(3, 4), c2(1, 2);
Complex c3 = c1 + c2; // uses overloaded operator
[Link]();
return 0;
}
Example 3: Overloading ==
#include <iostream>
using namespace std;
class Student {
private:
int rollNo;
public:
Student(int r) : rollNo(r) {}
// Overload ==
bool operator==(const Student& s) {
return rollNo == [Link];
}
};
int main() {
Student s1(101), s2(101), s3(102);
if (s1 == s2)
cout << "s1 and s2 are equal" << endl;
else
cout << "s1 and s2 are not equal" << endl;
if (s1 == s3)
cout << "s1 and s3 are equal" << endl;
else
cout << "s1 and s3 are not equal" << endl;
return 0;
}
4. Difference: Function vs Operator Overloading
Feature Function Overloading Operator Overloading
Same function name, different Redefining operators for user-
Definition
parameters defined types
Purpose Convenience, readability Extend operators for objects
add(int, int) and add(double,
Example double)
Overloading + for Complex class
Compile-time
Yes (resolved by arguments) Yes (resolved by operands)
decision
5. Real-Life Analogy
Function Overloading → Like the word "run" (you can run a race, run a machine, run a
program → same word, different meaning).
Operator Overloading → Like + sign (adds numbers, concatenates strings, merges lists
→ same symbol, different actions).
6. Key Points
Overloading provides compile-time polymorphism.
Function Overloading → Same function, different arguments.
Operator Overloading → Redefining operators for classes.
Cannot overload ::, . , .*, sizeof, ?:.
Final Takeaway
2. Syntax
class Base {
// data members & member functions
};
void showDetails() {
cout << "Name: " << name << ", Age: " << age << endl;
}
};
void showStudent() {
cout << "Roll No: " << rollNo << endl;
}
};
int main() {
Student s1;
[Link] = "Loki"; // inherited
[Link] = 21; // inherited
[Link] = 101; // own member
Student automatically gets access to name, age, and showDetails() from Person.
class A { };
class B : public A { };
class A { };
class B : public A { };
class C : public B { };
class A { };
class B { };
class C : public A, public B { };
class A { };
class B : public A { };
class C : public A { };
class → private
struct → public
class LivingBeing {
public:
void breathe() {
cout << "Breathing..." << endl;
}
};
int main() {
Student s;
[Link](); // from LivingBeing
[Link](); // from Person
[Link](); // own
return 0;
}
class Teacher {
public:
void teach() {
cout << "Teaching..." << endl;
}
};
class Researcher {
public:
void research() {
cout << "Researching..." << endl;
}
};
int main() {
Professor p;
[Link](); // from Teacher
[Link](); // from Researcher
[Link]();// own
return 0;
}
class Base {
public:
Base() { cout << "Base Constructor\n"; }
~Base() { cout << "Base Destructor\n"; }
};
int main() {
Derived d;
return 0;
}
Output:
Base Constructor
Derived Constructor
Derived Destructor
Base Destructor
9. Advantages of Inheritance
Code reusability (don’t rewrite).
Easier maintenance.
Supports polymorphism.
Models real-world relationships.
2. Function Overriding
Definition: Function overriding occurs when a derived class has a function with the
same name, return type, and parameters as in the base class.
Used to provide a specialized implementation.
Achieved using inheritance + virtual functions.
3. Syntax
class Base {
public:
virtual void show() { // base version
cout << "Base class function" << endl;
}
};
int main() {
Animal *a; // base class pointer
a = new Cat();
a->sound(); // Meow!
delete a;
return 0;
}
Here:
int main() {
Base *b = new Derived();
b->display(); // still works because called through Base pointer
delete b;
return 0;
}
#include <iostream>
using namespace std;
class Shape {
public:
virtual void draw() {
cout << "Drawing a generic shape" << endl;
}
};
int main() {
Circle c;
[Link]();
return 0;
}
Output:
Drawing a circle
Drawing a generic shape
7. Key Points
Overloading vs Overriding
o Overloading = Same name, different parameters (compile-time polymorphism).
o Overriding = Same name, same parameters, redefined in derived (runtime
polymorphism).
Virtual functions ensure correct overriding behavior.
override keyword (C++11) → helps compiler check correctness.
Access specifiers (public, protected, private) control visibility of overridden
functions.
Overriding = specialization → derived class provides more specific behavior.
8. Real-Life Analogy
Base class: "Vehicle" with function move().
Derived classes:
o Car::move() → "Drives on road".
o Boat::move() → "Sails on water".
o Airplane::move() → "Flies in the sky".
Final Takeaway
Poly = many
Morph = forms
class Print {
public:
void show(int x) {
cout << "Integer: " << x << endl;
}
void show(double y) {
cout << "Double: " << y << endl;
}
void show(string s) {
cout << "String: " << s << endl;
}
};
int main() {
Print p;
[Link](10); // Integer
[Link](3.14); // Double
[Link]("Hello"); // String
return 0;
}
class Complex {
int real, imag;
public:
Complex(int r=0, int i=0) : real(r), imag(i) {}
void display() {
cout << real << " + " << imag << "i" << endl;
}
};
int main() {
Complex c1(3,4), c2(1,2);
Complex c3 = c1 + c2; // Uses overloaded +
[Link](); // 4 + 6i
return 0;
}
class Animal {
public:
virtual void sound() { // virtual = enable runtime polymorphism
cout << "Some generic animal sound" << endl;
}
};
int main() {
Animal* a; // Base class pointer
a = new Dog();
a->sound(); // Bark!
a = new Cat();
a->sound(); // Meow!
delete a;
return 0;
}
Here:
5. Polymorphism Diagram
Polymorphism
/ \
Compile-time Runtime
(Early Binding) (Late Binding)
----------------- -----------------
- Function Overloading - Virtual Functions
- Operator Overloading - Function Overriding
- Templates
6. Real-Life Analogies
Compile-time Polymorphism → “Power button”
o On TV → turns it on.
o On Laptop → boots the system.
o On Fan → starts the motor.
Same "action" but compiler decides based on context (device).
Runtime Polymorphism → “MakeSound()” for Animals
o Dog → Bark.
o Cat → Meow.
o Cow → Moo.
Same "function" but decided at runtime depending on object type.
7. Key Points
Compile-time polymorphism = overloading & templates.
Runtime polymorphism = overriding with virtual functions.
Virtual functions enable dynamic dispatch.
Polymorphism increases flexibility, reusability, and scalability of code.
Final Takeaway
Definition:
A virtual function is a member function in a base class declared with the keyword virtual,
which allows it to be overridden in derived classes and ensures runtime (dynamic)
polymorphism.
2. Syntax
class Base {
public:
virtual void display() { // virtual function
cout << "Base display" << endl;
}
};
class Base {
public:
void show() { // NOT virtual
cout << "Base show()" << endl;
}
};
int main() {
Base* b;
Derived d;
b = &d;
class Base {
public:
virtual void show() { // Virtual function
cout << "Base show()" << endl;
}
};
int main() {
Base* b;
Derived d;
b = &d;
class Animal {
public:
virtual void sound() { cout << "Some generic sound" << endl; }
};
int main() {
Animal* a;
a = new Dog();
a->sound(); // Bark!
a = new Cat();
a->sound(); // Meow!
delete a;
return 0;
}
7. Virtual Destructors
When using inheritance with dynamic memory, destructors in the base class should be virtual,
otherwise only the base destructor runs, causing memory leaks.
Example 4: Without Virtual Destructor
#include <iostream>
using namespace std;
class Base {
public:
~Base() { cout << "Base Destructor" << endl; }
};
int main() {
Base* b = new Derived();
delete b; // Only Base destructor runs!
return 0;
}
class Base {
public:
virtual ~Base() { cout << "Base Destructor" << endl; }
};
int main() {
Base* b = new Derived();
delete b; // Derived + Base destructor run (correct)
return 0;
}
8. Real-Life Analogy
Base class: Shape with draw().
Derived classes:
o Circle::draw() → Draws circle.
o Rectangle::draw() → Draws rectangle.
With virtual draw(), the correct shape gets drawn at runtime, even if we handle all objects
via a Shape* pointer.
Final Takeaway
1. Abstract Classes
Definition
An abstract class in C++ is a class that cannot be instantiated and is meant only to be a base
class for other classes.
It contains at least one pure virtual function.
class Shape {
public:
virtual void draw() = 0; // Pure virtual function
};
s = new Circle();
s->draw(); // Drawing Circle
s = new Square();
s->draw(); // Drawing Square
delete s;
return 0;
}
Here:
Shape is abstract.
It forces derived classes (Circle, Square) to implement draw().
Achieves runtime polymorphism.
When we use virtual functions, C++ needs a mechanism to decide at runtime which function to
call (base or derived).
This mechanism is the vtable (virtual table).
1. For every class with virtual functions, the compiler creates a vtable.
2. The vtable is basically an array of function pointers.
3. Each object of the class stores a hidden vptr (virtual pointer) that points to its class’s
vtable.
4. When a virtual function is called via a base pointer, the program looks up the function
address from the vtable.
class Base {
public:
virtual void show() { cout << "Base show()" << endl; }
virtual void print() { cout << "Base print()" << endl; }
};
int main() {
Base* b;
Derived d;
b = &d;
b->show(); // Derived show()
b->print(); // Derived print()
return 0;
}
Base vtable:
show() --> Base::show
print() --> Base::print
Derived vtable:
show() --> Derived::show
print() --> Derived::print
b = &d;
o b->show() → looks up Derived::show in derived’s vtable.
o b->print() → looks up Derived::print.
3. Example 3: Partial Overriding
If a derived class overrides only one function, its vtable contains a mix:
Derived2’s vtable:
4. Real-Life Analogy
Abstract Class: Think of it like a blueprint (House plan). You can’t "live" in a blueprint
directly, but you can build real houses (derived classes) from it.
vtable: Think of it as a directory of contacts. When you call a function, C++ checks the
right address in the "directory" (vtable) depending on the object’s actual type.
Final Takeaway
1. What is a Pointer?
A pointer is a special type of variable that stores the memory address of another variable.
Instead of holding a value directly, it points to the location where the value is stored.
int main() {
int x = 10;
int* ptr = &x; // pointer stores address of x
return 0;
}
Output (example):
Value of x: 10
Address of x: 0x61ff0c
Pointer ptr stores: 0x61ff0c
Value at ptr (dereferencing): 10
4. Important Operators
& (Address-of operator) → gives the address of a variable.
* (Dereference operator) → accesses the value stored at a pointer’s address.
int* p = nullptr;
2. Void Pointer
void* p;
int a = 5;
p = &a;
3. Pointer to Pointer
int x = 5;
int* p = &x;
int** pp = &p;
cout << **pp; // 5
4. Wild Pointer
int* p; // uninitialized
*p = 10; // ❌ Undefined behavior
5. Dangling Pointer
int main() {
int arr[3] = {10, 20, 30};
int* p = arr;
return 0;
}
void update(int* p) {
*p = *p + 5; // modifies original value
}
int main() {
int x = 10;
update(&x);
cout << "Updated x: " << x << endl; // 15
return 0;
}
8. Real-Life Analogy
Variable = House (stores value = furniture).
Address = House Number.
Pointer = Person carrying the house number (knows where the furniture is).
Dereferencing = Going to the house and checking the furniture.
9. Key Points
Pointers hold addresses, not values.
Use * to dereference (access the value).
Use & to get a variable’s address.
Always initialize pointers (nullptr).
Be careful of wild and dangling pointers.
Pointers are powerful but need careful handling (manual memory).
Final Takeaway
1. Introduction
A pointer to pointer (also called double pointer) is a pointer that stores the address of another
pointer.
Instead of pointing directly to a variable, it points to a pointer that points to the variable.
2. Syntax
dataType** ptr2;
3. Memory Diagram
int x = 10;
int* p = &x; // pointer to int
int** pp = &p; // pointer to pointer
Representation:
x = 10
p = address of x (&x)
pp = address of p (&p)
So:
x → 10
*p → 10
*pp → address of x
**pp → 10
4. Example 1: Basic Pointer to Pointer
#include <iostream>
using namespace std;
int main() {
int x = 42;
int* p = &x; // pointer to int
int** pp = &p; // pointer to pointer
return 0;
}
Output (example):
Value of x: 42
Value using *p: 42
Value using **pp: 42
Address of x: 0x61ff08
Pointer p stores: 0x61ff08
Pointer pp stores: 0x61ff04
int main() {
int x = 5;
int* p = &x;
int** pp = &p;
Output:
Before: 5
After: 20
**pp gives access to x.
#include <iostream>
using namespace std;
int main() {
int* p = nullptr;
int main() {
int arr[3] = {10, 20, 30};
int* p = arr; // pointer to first element
int** pp = &p; // pointer to pointer
return 0;
}
8. Real-Life Analogy
Variable = House (stores value).
Pointer = Person with house address.
Pointer to Pointer = Person who knows the person holding the house address.
9. Key Points
* = single pointer → stores address of variable.
** = double pointer → stores address of a pointer.
Useful in:
o Dynamic memory allocation.
o Passing pointers to functions.
o Multi-dimensional arrays.
o Complex data structures (linked lists, trees, graphs).
Final Takeaway
1. Introduction
A string in C++ can be represented in two ways:
1. C-style string → Character array ending with '\0'.
2. C++ string class (std::string).
Pointers make it possible to work with string arrays efficiently by directly pointing to
characters or arrays of strings.
int main() {
char str1[] = "Hello"; // stored as array of chars
char* str2 = "World"; // pointer to string literal
return 0;
}
int main() {
char str[] = "Pointer";
int main() {
char fruits[3][10] = {"Apple", "Banana", "Cherry"};
int main() {
const char* fruits[] = {"Apple", "Banana", "Cherry"};
int main() {
char str[] = "Hello";
char* p = str;
return 0;
}
If you try the same with char* p = "Hello"; → it’s undefined behavior, because string
literals are read-only.
int main() {
const char* cities[] = {"London", "Paris", "Tokyo", "New York"};
const char** p = cities; // pointer to array of string pointers
return 0;
}
Final Takeaway
Pointers and string arrays are deeply connected since strings in C are just character
arrays with \0 terminator.
Using pointers makes string handling efficient and flexible, but also requires careful
memory management.
Void Pointers and Function Pointers in C++
A void pointer (also called a generic pointer) is a special pointer that can store the address of
any data type, but it cannot be dereferenced directly without typecasting.
Syntax
void* ptr;
int main() {
int a = 10;
double b = 5.5;
char c = 'Z';
void* ptr;
ptr = &a;
cout << "Integer: " << *(int*)ptr << endl;
ptr = &b;
cout << "Double: " << *(double*)ptr << endl;
ptr = &c;
cout << "Char: " << *(char*)ptr << endl;
return 0;
}
Output:
Integer: 10
Double: 5.5
Char: Z
void* can point to any type, but we must cast before dereferencing.
Real-Life Analogy
Imagine void* as a locker that can hold any type of object, but before using it, you must open it
with the right key (typecasting).
2. Function Pointers
Definition
Syntax
returnType (*ptrName)(parameterTypes);
void greet() {
cout << "Hello from function!" << endl;
}
int main() {
void (*fp)(); // function pointer declaration
fp = &greet; // assign address of function
return 0;
}
Output:
int main() {
int (*fp)(int, int); // function pointer declaration
fp = add;
cout << "Sum: " << fp(5, 3) << endl; // 8
fp = multiply;
cout << "Product: " << fp(5, 3) << endl; // 15
return 0;
}
int main() {
compute(10, 5, add); // Result: 15
compute(10, 5, sub); // Result: 5
return 0;
}
#include <iostream>
using namespace std;
int main() {
int (*ops[])(int, int) = {add, sub, mul};
return 0;
}
Final Takeaway
Void Pointers = Generic pointers → can point to any type (must typecast before use).
Function Pointers = Special pointers → store function addresses, enabling indirect
function calls and callbacks.
Standard Template Library (STL) in C++
1. Introduction
The Standard Template Library (STL) in C++ is a collection of predefined classes and
functions that implement common data structures and algorithms.
It saves time because you don’t have to write everything from scratch.
2. Components of STL
STL has 4 major components:
3. Containers in STL
Containers are objects that store data.
They are divided into three categories:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v = {1, 2, 3, 4};
v.push_back(5); // add at end
#include <iostream>
#include <map>
using namespace std;
int main() {
map<int, string> students;
students[101] = "Alice";
students[102] = "Bob";
#include <iostream>
#include <unordered_set>
using namespace std;
int main() {
unordered_set<int> s = {1, 2, 3, 2, 1};
for (int x : s) cout << x << " "; // order not guaranteed
return 0;
}
4. Iterators
Iterators act like pointers to container elements.
Types:
o Input iterators
o Output iterators
o Forward iterators
o Bidirectional iterators
o Random access iterators
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v = {10, 20, 30};
vector<int>::iterator it;
for (it = [Link](); it != [Link](); ++it) {
cout << *it << " ";
}
return 0;
}
5. Algorithms
STL provides many ready-to-use algorithms inside <algorithm> header.
Examples:
sort([Link](), [Link]())
reverse([Link](), [Link]())
count([Link](), [Link](), 5)
find([Link](), [Link](), 10)
binary_search([Link](), [Link](), key)
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main() {
vector<int> v = {5, 2, 8, 1, 3};
sort([Link](), [Link]());
for (int x : v) cout << x << " ";
return 0;
}
6. Functors
A functor is a class that overloads the () operator, making objects callable like
functions.
Used with STL algorithms for custom behavior.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct Square {
void operator()(int x) {
cout << x * x << " ";
}
};
int main() {
vector<int> v = {1, 2, 3};
for_each([Link](), [Link](), Square());
return 0;
}
8. Real-Life Analogy
Think of STL as a toolbox:
Would you like me to prepare a topic-wise coding exercise sheet (like small tasks using
vector, set, map, etc.) so your students can practice STL hands-on?