CPP NOTES (Units 1 & 2)
CPP NOTES (Units 1 & 2)
C C++
C is (mostly) a subset of C++. C++ is (mostly) a superset of C.
Has 59 Keywords Has 81 Keywords
For the development of code, C C++ is known as hybrid language
supports procedural programming. because C++ supports both procedural
and object-oriented programming
paradigms.
Data and functions are separated in C because Data and functions are encapsulated
it is a procedural programming language. together in form of an object in C++.
C is a function driven language because C is a C++ is an object driven language because
procedural programming language. it is an object-oriented programming.
Namespace features are not present inside the Namespace is used by C++, which avoid
C. name collisions.
Standard IO header is stdio.h and Standard IO header is iostream.h and
uses scanf() and printf() functions are used for uses cin and cout are used for
input/output in C. input/output in C++.
Does not support virtual and friend functions Has Virtual and Friend functions
Functions in C are not defined inside structures. Functions can be used inside a structure
in C++.
C structures don’t have access modifiers. C++ structures have access modifiers.
Object-oriented programming can be defined as a programming model which is based upon the
concept of objects. Objects contain data in the form of attributes and code in the form of
methods. In object-oriented programming, computer programs are designed using the concept
of objects that interact with the real world. Object-oriented programming languages are various
but the most popular ones are class-based, meaning that objects are instances of classes,
which also determine their types.
Creating a class
To create a class, use the class keyword:
Creating an object
In C++, an object is created from a class. We have already created the class named MyClass ,
so now we can use this to create objects.
To create an object of MyClass , specify the class name, followed by the object name.
To access the class attributes ( myNum and myString ), use the dot syntax ( . ) on the object:
int main() {
MyClass myObj; // Create an object of MyClass
4 Pillars of OOPs
**Class**
The building block of C++ that leads to Object-Oriented programming is a Class. It is a user-
defined data type, which holds its own data members and member functions, which can be
accessed and used by creating an instance of that class. A class is like a blueprint for an object.
For Example: Consider the Class of Cars. There may be many cars with different names and
brands but all of them will share some common properties like all of them will have 4 wheels,
Speed Limit, Mileage range, etc. So here, the Car is the class, and wheels, speed limits, and
mileage are their properties.
A Class is a user-defined data type that has data members and member functions.
Data members are the data variables and member functions are the functions used to
manipulate these variables together these data members and member functions define the
properties and behavior of the objects in a Class.
In the above example of class Car, the data member will be speed limit, mileage, etc and
member functions can apply brakes, increase speed, etc.
We can say that a **Class in C++** is a blueprint representing a group of objects which
shares some common properties and behaviors.
**Object**
An Object is an identifiable entity with some characteristics and behavior. An Object is an
instance of a Class. When a class is defined, no memory is allocated but when it is instantiated
(i.e. an object is created) memory is allocated.
Objects take up space in memory and have an associated address like a record in pascal or
structure or union. When a program is executed the objects interact by sending messages to
one another. Each object contains data and code to manipulate the data. Objects can interact
without having to know details of each other’s data or code, it is sufficient to know the type of
message accepted and the type of response returned by the objects.
To know more about C++ Objects and Classes, refer to this article – C++ Classes and Objects
Data Types
Data types specify the type of data that a variable can store. Whenever a variable is defined in
C++, the compiler allocates some memory for that variable based on the data type with which it
is declared as every data type requires a different amount of memory.
In C++, data types are classified into the following types:
### Aspect ### Abstract Data Types (ADTs) ### User-Defined Data Types
(UDTs)
Definition Defines a class of objects and the A custom data type created by
operations that can be performed on combining or extending existing
them, along with their expected primitive types, specifying both
behavior (semantics), but without structure and operations.
specifying implementation details.
Focus What operations are allowed and how How data is organized in
they behave, without dictating how memory and how operations
they are implemented. are executed.
Purpose Provides an abstract model to define Allows programmers to create
data structures in a conceptual way. concrete implementations of
data structures using primitive
types.
Implementation Does not specify how operations are Specifies how to create and
Details implemented or how data is structured. organize data types to
implement the structure.
Usage Used to design and conceptualize Used to implement data
data structures. structures that realize the
abstract concepts defined by
ADTs.
Example List ADT, Stack ADT, Queue ADT. Structures, classes,
enumerations, records.
Structure
A UDT. A structure creates a data type that can be used to group items of possibly different
types into a single type.
#include <iostream>
using namespace std;
// Declaring structure
struct Basket {
int i;
char c;
};
int main() {
Union
UDT, used to group data of different type into a single type. But in union, all members share the
same memory location.
#include <iostream>
using namespace std;
// Declaration of union is same as the structures
union A {
int i;
char c;
};
int main() {
// A union variable t
A a;
// Assigning value to c, i will also
// assigned the same
a.c = 'A';
#include <iostream>
using namespace std;
// Declaring enum
enum Week { Mon, Tue, Wed, Thur, Fri, Sat, Sun };
int main() {
#include <iostream>
using namespace std;
int main() {
// Declaring variables using new type names
f x = 3.14;
integer y = 42;
cout << "Float Value: " << x << endl;
cout << "Integer Value: " << y;
return 0;
}
Attributes (also called data members or properties) are variables that store the state or
characteristics of an object. They are typically declared as member variables inside a class.
Methods (also called member functions) are functions that define the behavior of a class.
They operate on the attributes and provide functionality.
#include <iostream>
using namespace std;
class Car {
public:
// Attributes
string brand;
int speed;
// Method
void displayInfo() {
cout << "Brand: " << brand << ", Speed: " << speed << " km/h" <<
endl;
}
};
int main() {
Car myCar;
myCar.brand = "Toyota";
myCar.speed = 120;
myCar.displayInfo(); // Calls the method
return 0;
}
Local Classes
A class declared inside a function becomes local to that function and is called Local Class in
C++.
A local class name can only be used locally i.e., inside the function and not outside it.
The methods of a local class must be defined inside it only.
A local class can have static functions but, not static data members. Example:
#include <iostream>
using namespace std;
void fun() {
// Local class inside the function
class Test {
public:
// Static function allowed
static void staticFunction() {
cout << "Static function inside local class." << endl;
}
// Static data members are NOT allowed in local classes
// static int staticVar; // ❌
This would cause a compilation error
void normalFunction() {
cout << "Normal function inside local class." << endl;
}
};
// Creating an object of the local class
Test obj;
obj.normalFunction();
// Calling the static function
Test::staticFunction();
}
int main() {
fun();
return 0;
}
A static data member is a variable that is shared among all objects of a class. It is:
#include <iostream>
using namespace std;
class Test {
public:
static int count; // Declaration of static data member
Test() {
count++; // Increment count whenever an object is created
}
void showCount() {
cout << "Count: " << count << endl;
}
};
int main() {
Test obj1, obj2, obj3;
return 0;
}
Can access only static data members (not regular instance variables).
Belongs to the class rather than any specific object.
Can be called using the class name ( ClassName::FunctionName() ).
Does not have a this pointer because it is not tied to any object.
Example
#include <iostream>
using namespace std;
class Test {
public:
static int count; // Static data member
int main() {
Test::showCount(); // Calling static function without creating an
object
Test obj;
obj.showCount(); // Can also be called using an object
return 0;
}
Key Differences:
#include <iostream>
using namespace std;
int main() {
Example:
#include <iostream>
using namespace std;
class A {
public:
void show(); // Function declaration
};
int main() {
A obj;
obj.show(); // Calls A::show()
return 0;
}
void A::show() defines the show() function outside the class using :: .
If two different classes have functions with the same name, you use the scope resolution
operator to specify which class’s function to call.
Example:
#include <iostream>
using namespace std;
class A {
public:
void show() {
cout << "Function from Class A" << endl;
}
};
class B {
public:
void show() {
cout << "Function from Class B" << endl;
}
};
int main() {
A objA;
B objB;
return 0;
}
Since both A and B have a function show() , we use object names ( objA.show() and
objB.show() ) to call the correct function.
However, if no object is used, and we have static functions, we can use
ClassName::FunctionName() .
Example:
#include <iostream>
using namespace std;
class A {
public:
static void show() {
cout << "Static function from Class A" << endl;
}
};
class B {
public:
static void show() {
cout << "Static function from Class B" << endl;
}
};
int main() {
A::show(); // Calls A's static function
B::show(); // Calls B's static function
return 0;
}
4.1 Accessing global and local variables with the same name:
#include <iostream>
using namespace std;
int main() {
int x = 20; // Local variable
cout << "Local x: " << x << endl; // 20
cout << "Global x: " << ::x << endl; // 10
return 0;
}
::x refers to the global variable, while x refers to the local one.
4.1 Accessing global and local variables with the same name:
#include <iostream>
namespace ns {
void show() {
std::cout << "Inside namespace ns" << std::endl;
}
}
int main() {
ns::show(); // Calls function inside namespace
return 0;
}
::x refers to the global variable, while x refers to the local one.
Key Takeaways:
Instantation
Instantiation in C++ refers to the creation of an object from a class. It involves allocating
memory for the object and executing the class's constructor to initialize its members. There are
two primary ways to instantiate objects in C++:
#include <iostream>
using namespace std;
class Car {
public:
void show() {
cout << "This is a static car object." << endl;
}
};
int main() {
Car myCar; // Static instantiation (allocated on stack)
myCar.show();
return 0;
} // myCar is automatically destroyed when main() ends
#include <iostream>
using namespace std;
class Car {
public:
void show() {
cout << "This is a dynamically created car object." << endl;
}
};
int main() {
Car* myCar = new Car(); // Dynamic instantiation (allocated on heap)
myCar->show();
Car* myCar = new Car(); creates a Car object dynamically on the heap.
The object persists until we manually delete it using delete myCar; .
is equivalent to
Car* myCar = new Car();
(*myCar)show();
as myCar is not the object but a pointer to the dynamically allocated object.
similarly ,
this->
is same as using
(*this)
Constructors
Constructors are special member functions that are automatically called when an object is
instantiated. They initialize the object's state. If no constructor is defined, the compiler provides
a default constructor.
Key features
Has the same name as the class.
No return type (not even void ).
Can be parameterized or default.
Can be overloaded.
Types of Constructors
1. Parametrized Constructors
takes in parameters/args
2. Unparametrized Constructor
takes no params
3. Copy Constructor
Example of constructors:
#include <iostream>
using namespace std;
class Car {
private:
string brand;
public:
// Default Constructor
Car() {
this->brand = "Unknown"; // Using 'this' to refer to class member
cout << "Default Constructor Called" << endl;
}
// Parameterized Constructor
Car(string brand) {
this->brand = brand; // Using 'this' to differentiate class member
and parameter
cout << "Parameterized Constructor Called" << endl;
}
// Copy Constructor
Car(const Car &c) {
this->brand = c.brand; // Copying brand from existing object
cout << "Copy Constructor Called" << endl;
}
int main() {
Car car1; // Calls Default Constructor
car1.show();
return 0;
}
Destructors
A destructor is a special function that is automatically called when an object goes out of
scope or is deleted.
Key features
Has the same name as the class, but prefixed with ~ .
No parameters and no return type.
Cannot be overloaded.
Used to release resources (like memory, file handles, etc.).
Example:
#include <iostream>
using namespace std;
class Car {
public:
Car() {
cout << "Constructor Called" << endl;
}
~Car() {
cout << "Destructor Called" << endl;
}
};
int main() {
Car car1; // Constructor called automatically
return 0; // Destructor called automatically when main() ends
}
Array of objects
In C++, you can create an array of objects to store multiple objects of the same class.
#include <iostream>
using namespace std;
class Student {
public:
string name;
int age;
void showDetails() {
cout << "Name: " << name << ", Age: " << age << endl;
}
};
int main() {
Student s[2]; // Array of 2 Student objects
s[0].setDetails("Alice", 20);
s[1].setDetails("Bob", 22);
s[0].showDetails();
s[1].showDetails();
return 0;
}
#include <iostream>
using namespace std;
class Car {
private:
string brand;
public:
Car(string b) { brand = b; }
return 0;
}
Constant Objects
A constant object is an object whose members cannot be modified after initialization.
#include <iostream>
using namespace std;
class Circle {
private:
double radius;
public:
Circle(double r) { radius = r; }
int main() {
const Circle c1(5.5); // Constant object
c1.showRadius(); // Can only call constant member functions
return 0;
}
#include <iostream>
using namespace std;
class Car {
public:
string brand;
Car(string b) {
brand = b;
cout << "Car Created: " << brand << endl;
}
void show() {
cout << "Car Brand: " << brand << endl;
}
};
int main() {
Car* myCar = new Car("Toyota"); // Allocating memory dynamically
myCar->show(); // Access using pointer
#include <iostream>
using namespace std;
int main() {
int* arr = new int[5]; // Allocating an array of 5 integers
Encapsulation
The process of grouping data members and corresponding methods into a single unit is known
as Encapsulation. It is an important part of object-oriented programming. We can create a fully
encapsulated class by making all the data members private. If the data members are private, it
can only be accessible within the class; no other class can access that class’s data members.
Example:
#include <iostream>
#include <string>
using namespace std;
class Student{
private:
string name;
int age;
int height;
public:
int getAge(){
return this->age;
}
};
int main() {
Student stud1;
cout<<"program working fine"<<endl;
return 0;
}
Advantages of Encapsulation
1. Encapsulation is a way to achieve data hiding because other classes will not be able to
access the data through the private data members.
2. In Encapsulation, we can hide the data’s internal information, which is better for security
concerns.
3. By encapsulation, we can make the class read-only. The code reusability is also an
advantage of encapsulation.
4. Encapsulated code is better for unit testing.
5. 1. It helps to control the modification of our data members.
Private: Private access specifier means that the member function or data member can only
be accessed by other member functions of the same class.
Protected: A protected access specifier means that the member function or data member
can be accessed by other member functions of the same class or by derived classes.
Public: Public access specifier means that the member function or data member can be
accessed by any code.
By default, all data members and member functions of a class are made private by the
compiler.
Inheritance
Inheritance is one of the key features of Object-oriented programming in C++. It allows us to
create a new class (derived class) from an existing class (base class).
The derived class inherits the fe atures from the base class and can have additional features of
its own.
Inheritance allows us to define a class in terms of another class, which makes it easier to create
and maintain an application. This also provides an opportunity to reuse the code functionality
and fast implementation time.
When creating a class, instead of writing completely new data members and member functions,
the programmer can designate that the new class should inherit the members of an existing
class. This existing class is called the base class, and the new class is referred to as the
derived class.
Syntax:
class parent_class {
//Body of parent class
};
Here, child_class is the name of the subclass, access_mode is the mode in which you want to
inherit this sub-class, for example, public, private, etc., and parent_class is the name of the
superclass from which you want to inherit the subclass.
Modes of inheritance
1. Public mode: If we derive a subclass from a public base class. Then, the base class’s public
members will become public in the derived class, and protected class members will become
protected in the derived class.
2. Protected mode: If we derive a subclass from a Protected base class. Then both public
members and protected members of the base class will become protected in the derived
class.
3. Private mode: If we derive a subclass from a Private base class. Then both public members
and protected members of the base class will become Private in the derived class.
Base Class Member access specifier Public Protected Private
Public Public Protected Private
Protected Protected Protected Private
Private Not accessible Not accessible Not accessible
Example:
#include <iostream>
#include <string>
using namespace std;
class Human{
public:
int height;
int weight;
int age;
int getAge(){
return this->age;
}
void setWeight(int w){
this->weight = w;
}
};
void sleep() {
cout<<"Male Sleeping"<<endl;
}
};
int main() {
Male object1;
cout<<object1.age<<endl;
cout<<object1.weight<<endl;
cout<<object1.height<<endl; //all these are member funcs of human class
but can still be accessed as Male
inherits human class
object1.setWeight(84);
cout<<object1.weight<<endl;
object1.sleep();
return 0;
}
if the access modifier, for example is set to protected we will need to access human member
funcs through the Male class as shown below:
void sleep() {
cout<<"Male Sleeping"<<endl;
}
int getheight(){
return this->height;
}
};
int main() {
Male object1;
//cout<<object1.height<<endl; this is wrong
cout<<object1.getHeight()<<endl;// this is right
return 0;
}
Types of Inheritance
1. Single inheritance
In single inheritance, a class is allowed to inherit from only one class. i.e. one base class is
inherited by one derived class only. Example: The Human and male classes implemented
earlier.
2. Multilevel Inheritance
In this type of inheritance, a derived class is created from another derived class and that
derived class can be derived from a base class or any other derived class. There can be any
number of levels.
Syntax:
#include <iostream>
#include <string>
using namespace std;
class Animal{
public:
int age;
int weight;
void speak(){
cout<<"speaking"<<endl;
}
};
};
};
int main() {
Labrador sheru;
sheru.speak();
return 0;
}
3. Multiple Inheritance
Multiple Inheritance is a feature of C++ where a class can inherit from more than one class. i.e
one subclass is inherited from more than one base class.
Syntax:
Example:
#include<iostream>
using namespace std;
class Animal {
public:
int age;
int weight;
void bark() {
cout << "Barking " << endl;
}
};
class Human {
public:
string color;
void speak() {
cout << "Speaking " << endl;
}
};
//Multiple Inheritance
class Hybrid: public Animal, public Human {
};
int main() {
Hybrid obj1;
obj1.speak();
obj1.bark();
return 0;
}
#include<iostream>
using namespace std;
class A {
public:
void func1() {
cout << "Inside Funcion 1" << endl;
}
};
class B: public A {
public:
void func2() {
cout << "Inside Funcion 2" << endl;
}
};
class C: public A {
public:
void func3() {
cout << "Inside Funcion 3" << endl;
}
};
int main() {
A object1;
object1.func1();
B object2;
object2.func1();
object2.func2();
C object3;
object3.func1();
object3.func3();
return 0;
}
5. Hybrid Inheritance
Hybrid Inheritance is implemented by combining more than one type of inheritance. For
example: Combining Hierarchical inheritance and Multiple Inheritance will create hybrid
inheritance in C++
There is no particular syntax of hybrid inheritance. We can just combine two of the above
inheritance types.
Inheritance ambiguity
In multiple inheritances, when one class is derived from two or more base classes then there
may be a possibility that the base classes have functions with the same name, and the derived
class may not have functions with that name as those of its base classes. If the derived class
object needs to access one of the similarly named member functions of the base classes then it
results in ambiguity because the compiler gets confused about which base’s class member
function should be called.
Solution:
Scope resolution operator ::
#include<iostream>
using namespace std;
class A {
public:
void func() {
cout << " I am A" << endl;
}
};
class B {
public:
void func() {
cout << " I am B" << endl;
}
};
};
int main() {
C obj;
//obj.func();
obj.A::func() ;
obj.B::func();
return 0;
}
#include<iostream>
using namespace std;
class A {
public:
int x;
A() { x = 10; }
};
int main() {
D obj;
cout << obj.x << endl; // No ambiguity
return 0;
}
class Base {
public:
virtual void show() { cout << "Base class show()" << endl; }
};
Using virtual in the base class allows polymorphism, so calling show() on a Base* points
to the derived class method.
class Base {
public:
Base() { cout << "Base Constructor" << endl; }
};
int main() {
Derived obj;
return 0;
}
Output:
Base Constructor
Derived Constructor
Abstraction
Read this
Abstraction and Encapsulation difference
Aggregation vs. Composition vs. Classification
Hierarchies
These describe relationship between classes.
A weaker relationship where the contained object can exist independently of the container.
Example: A "Car" has an "Engine," but the engine can exist outside of the car.
class Engine {
public:
void start() { cout << "Engine started" << endl; }
};
class Car {
Engine* engine; // Pointer to an Engine object
public:
Car(Engine* eng) : engine(eng) {} // Aggregation (external ownership)
void start() { engine->start(); }
};
A stronger relationship where the contained object cannot exist independently of the
container.
Example: A "Human" has a "Heart"; if the human is destroyed, so is the heart.
class Heart {
public:
void beat() { cout << "Heart is beating" << endl; }
};
class Human {
Heart heart; // Direct ownership (composition)
public:
void live() { heart.beat(); }
};
class Mammal {
public:
void breathe() { cout << "Breathing..." << endl; }
};
Nested Classes
A nested class is a class which is declared in another enclosing class. A nested class is a
member and as such has the same access rights as any other member. The members of an
enclosing class have no special access to members of a nested class; the usual access rules
shall be obeyed.
For example, program 1 compiles without any error and program 2 fails in compilation.
Program 1:
#include<iostream>
int main()
{
}
Program 2:
#include<iostream>
int x;
int main()
{
Message passing
Message passing is a concept from Object-Oriented Programming (OOP) where objects
communicate by sending messages (function calls).
Example of objects communicating via function calls:
#include <iostream>
using namespace std;
class Messenger {
public:
void sendMessage(const string& message) {
cout << "Sending message: " << message << endl;
}
};
class User {
Messenger messenger;
public:
void notify() {
messenger.sendMessage("Hello, you have a notification!");
}
};
int main() {
User user;
user.notify();
return 0;
}
Here, User sends a message via the Messenger class, demonstrating message passing.
Friend Functions
A friend function allows external functions to access private/protected members of a class
without being a member of the class.
Example:
#include <iostream>
using namespace std;
class A {
private:
int x;
public:
A() : x(10) {}
int main() {
A obj;
showX(obj); // Calls friend function
return 0;
}
Output:
Value of x: 10
Although showX() is not a member of A , it can access its private variable x because it's
declared as a friend function.
Inline Functions
An inline function suggests to the compiler that the function should be expanded at the point
of call instead of performing a regular function call. This helps reduce function call overhead
for small functions.
Example:
#include <iostream>
using namespace std;
class Math {
public:
inline int square(int x) { return x * x; } // Inline function
};
int main() {
Math m;
cout << "Square of 5: " << m.square(5) << endl;
return 0;
}
Output:
Square of 5: 25
Since square() is an inline function, the compiler may replace m.square(5) with 5 * 5
directly, avoiding a function call.
#include <iostream>
using namespace std;
int main() {
int num = "Hello"; // ERROR: Type mismatch
cout << num << endl;
return 0;
}
Runtime
The phase when the compiled program is executed.
Errors like division by zero, accessing invalid memory, or infinite loops occur at
runtime.
Examples:
- Memory leaks
- Null pointer dereference
- Division by zero
Example of runtime error:
#include <iostream>
using namespace std;
int main() {
int a = 10, b = 0;
cout << (a / b) << endl; // ERROR: Division by zero at runtime
return 0;
}
#include <iostream>
using namespace std;
void myFunction() {
int x = 10; // Stored in stack
cout << x << endl;
}
int main() {
myFunction();
return 0;
}
#include <iostream>
using namespace std;
int main() {
int* ptr = new int(20); // Allocates memory in heap
cout << *ptr << endl;
delete ptr; // Frees memory
return 0;
}
Here:
void badFunction() {
int* ptr = new int(100);
// Forgot to delete ptr → Memory leak
}