0% found this document useful (0 votes)
28 views47 pages

CPP NOTES (Units 1 & 2)

The document outlines the differences between C and C++, highlighting C as a procedural language and C++ as a hybrid language that supports both procedural and object-oriented programming. It discusses the principles of procedural programming versus object-oriented programming, emphasizing the use of classes and objects in C++. Additionally, it covers data types, abstract data types, and provides examples of structures, unions, and enumerations in C++.

Uploaded by

Vishal Rai
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)
28 views47 pages

CPP NOTES (Units 1 & 2)

The document outlines the differences between C and C++, highlighting C as a procedural language and C++ as a hybrid language that supports both procedural and object-oriented programming. It discusses the principles of procedural programming versus object-oriented programming, emphasizing the use of classes and objects in C++. Additionally, it covers data types, abstract data types, and provides examples of structures, unions, and enumerations in C++.

Uploaded by

Vishal Rai
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
You are on page 1/ 47

CPP NOTES(Unit 1 && 2)

C and C++ Difference

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.

Procedural Programming vs OOPS


Procedural Programming can be defined as a programming model which is derived from
structured programming, based upon the concept of calling procedure. Procedures, also known
as routines, subroutines or functions, simply consist of a series of computational steps to be
carried out. During a program’s execution, any given procedure might be called at any point,
including by other procedures or itself.

Languages used in Procedural Programming:


FORTRAN, ALGOL, COBOL,

BASIC, Pascal and C.

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.

Languages used in Object-Oriented Programming:

Java, C++, C#, Python,

PHP, JavaScript, Ruby, Perl,

Objective-C, Dart, Swift, Scala.

Procedural Oriented Programming Object-Oriented Programming


In procedural programming, the program is In object-oriented programming, the
divided into small parts called functions. program is divided into small parts
called objects.
Procedural programming follows a top-down Object-oriented programming follows
approach. a bottom-up approach.
There is no access specifier in procedural Object-oriented programming has access
programming. specifiers like private, public, protected, etc.
Adding new data and functions is not easy. Adding new data and function is easy.
Procedural programming does not have any Object-oriented programming provides data
proper way of hiding data so it is less secure. hiding so it is more secure.
In procedural programming, overloading is Overloading is possible in object-oriented
not possible. programming.
In procedural programming, there is no In object-oriented programming, the
concept of data hiding and inheritance. concept of data hiding and inheritance is
used.
In procedural programming, the function is In object-oriented programming, data is
more important than the data. more important than function.
Procedural Oriented Programming Object-Oriented Programming
Procedural programming is based on Object-oriented programming is based on
the unreal world. the real world.
Procedural programming is used for Object-oriented programming is used for
designing medium-sized programs. designing large and complex programs.
Procedural programming uses the concept of Object-oriented programming uses the
procedure abstraction. concept of data abstraction.
Code reusability absent in procedural Code reusability present in object-oriented
programming, programming.
Examples: C, FORTRAN, Pascal, Basic, etc. Examples: C++, Java, Python, C#, etc.

Classes and Objects


Being an Object Oriented Programming language everything in C++ is associated with classes
and objects, along with its attributes and methods.
Attributes and methods are basically variables and functions that belongs to the class. These
are often referred to as "class members".
A class is a user-defined data type that we can use in our program, and it works as an object
constructor, or a "blueprint" for creating objects.

Creating a class
To create a class, use the class keyword:

class MyClass { // The class


public: // Access specifier
int myNum; // Attribute (int variable)
string myString; // Attribute (string variable)
};

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:

class MyClass { // The class


public: // Access specifier
int myNum; // Attribute (int variable)
string myString; // Attribute (string variable)
};

int main() {
MyClass myObj; // Create an object of MyClass

// Access attributes and set values


myObj.myNum = 15;
myObj.myString = "Some text";

// Print attribute values


cout << myObj.myNum << "\n";
cout << myObj.myString;
return 0;
}

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:

S. Type Description Data Types


No.
1 Basic Data Built-in or primitive data types that are used to int, float, double,
Types store simple values. char, bool, void
2 Derived Data Data types derived from basic types. Created array, pointer,
Types from the primitive data types and provide some reference,
additional functionality. function
3 User Defined Custom data types created by the programmer class, struct,
Data Types according to their need. union, typedef,
enum
Abstract data types
An Abstract Data Type (ADT) is a conceptual model that defines a set of operations and
behaviors for a data structure, without specifying how these operations are implemented or how
data is organized in memory. The definition of ADT only mentions what operations are to be
performed but not how these operations will be implemented. It does not specify how data will
be organized in memory and what algorithms will be used for implementing the operations. It is
called “abstract” because it provides an implementation-independent view.

Difference Between ADTs and UDTs

### 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() {

// Create an instance of structure


Basket a;

// Initialize structure members


a.i = 65;
a.c = 'A';
cout << a.c << ": " << a.i;
return 0;
}

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';

cout << "a.i: " << a.i << endl;


cout << "a.c: " << a.c;
return 0;
}
Enumeration
used to assign names to integral constants, the names make a program easy to read and
maintain.

#include <iostream>
using namespace std;

// Declaring enum
enum Week { Mon, Tue, Wed, Thur, Fri, Sat, Sun };

int main() {

// Creating enum variable


enum Week day;
// Assigning value to the variabe
day = Wed;
cout << day;
return 0;
}

Typedef and Using

#include <iostream>
using namespace std;

// Using typedef to define a new name for existing type


typedef float f;

// Using 'using' to define a new name for existing type


using integer = int;

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 and Methods


In C++ object-oriented programming (OOP), attributes and methods are key components of a
class:

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;
}

Static Data Members and functions

1. Static data members:

A static data member is a variable that is shared among all objects of a class. It is:

Declared using the static keyword inside the class.


Defined outside the class (unlike normal members).
Shared by all objects (i.e., it is not tied to a specific object).
Stored in static memory (not in each object’s memory).
Initialized only once and retains its value across all instances.

#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;
}
};

// Definition of static data member (must be done outside the class)


int Test::count = 0;

int main() {
Test obj1, obj2, obj3;

obj1.showCount(); // Output: Count: 3 (shared by all objects)


obj2.showCount(); // Output: Count: 3
obj3.showCount(); // Output: Count: 3

return 0;
}

static int count is shared by all instances of Test .


When new objects are created, count increases.
Since count is static, it is not tied to any object but belongs to the class.

2. Static Member functions


A static member function:

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

static void showCount() { // Static function


cout << "Count: " << count << endl;
}
};

int Test::count = 5; // Definition of static variable

int main() {
Test::showCount(); // Calling static function without creating an
object

Test obj;
obj.showCount(); // Can also be called using an object

return 0;
}

showCount() is a static function, so it can be called using Test::showCount() .


It can only access static int count because static functions cannot access non-static
members.

Key Differences:

Feature Static Data Member Static Member Function


Shared across ✅ Yes ✅ Yes
objects?
Requires an object ❌ No (can be accessed ❌ No (can be accessed using
to access? using ClassName::var ) ClassName::function() )

Can access non- ❌ No ❌ No


static members?
Needs to be ✅ Yes ❌ No
defined outside the
class?

State, Identity and behaviour of an object


An object has an identity, state, and behavior. Each object contains data and code to
manipulate the data.
Scope of object
Global and local just like other variables

#include <iostream>
using namespace std;

// Declaring first variable


int a = 10;

int main() {

// Declaring second variable


int b = 9;
// Accessing a and b variable in their scope
cout << a << " " << b;
return 0;
}

Scope Resolution operator


The scope resolution operator ( :: ) in C++ is used in several scenarios, However, its main
purpose is to define class members outside the class and distinguish between scopes.

1. Using Scope Resolution Operator to Define a Function Outside


the Class
When a member function is declared inside a class but defined outside, we use :: .

Example:

#include <iostream>
using namespace std;
class A {
public:
void show(); // Function declaration
};

// Function definition using scope resolution


void A::show() {
cout << "Function from Class A" << endl;
}

int main() {
A obj;
obj.show(); // Calls A::show()
return 0;
}

void A::show() defines the show() function outside the class using :: .

2. Using Scope Resolution Operator to Distinguish Between Two


Classes with the Same Function Name

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;

objA.show(); // Calls A::show()


objB.show(); // Calls B::show()

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() .

3. Using Scope Resolution Operator for Static Functions


If the function is static, it can be called directly using 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;
}

Since show() is a static function, we don’t need objects to call it.


Instead, we call it using A::show() or B::show() .

4. Other Uses of Scope Resolution Operator

4.1 Accessing global and local variables with the same name:

#include <iostream>
using namespace std;

int x = 10; // Global variable

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:

Use Case Example


Define a class function outside the class void ClassName::FunctionName()
{}

Call a function when two classes have the same ClassA::FunctionName();


function name
Call a static function directly without an object ClassName::StaticFunction();

Access a global variable when a local variable has ::globalVarName;


the same name
Access a function/variable inside a specific namespaceName::FunctionName();
namespace

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++:

Static Instantation(Stack instantation)


The object is created at compile time on the stack.
Memory is automatically allocated and deallocated.
The object lives until the function/block ends.
Example:

#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

Car myCar; is statically allocated (created on the stack).


It is automatically destroyed when main() ends.

Dynamic Instantation(Heap Instantation)


The object is created at runtime on the heap using new .
Memory must be manually deallocated using delete to prevent memory leaks.
The object persists until explicitly deleted.

#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();

delete myCar; // Free the allocated memory (manual deletion)


return 0;
}

Car* myCar = new Car(); creates a Car object dynamically on the heap.
The object persists until we manually delete it using delete myCar; .

The -> symbol

Used for Derefercing.


Example:

Car* myCar = new Car();


myCar->show();

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

Creates a new object by copying an existing one.


(Copy assignment operator is used)

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;
}

// Function to display car brand


void show() {
cout << "Car Brand: " << this->brand << endl;
}
};

int main() {
Car car1; // Calls Default Constructor
car1.show();

Car car2("Toyota"); // Calls Parameterized Constructor


car2.show();

Car car3 = car2; // Calls Copy Constructor


car3.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
}

Constructor runs when car1 is created.


Destructor runs when car1 goes out of scope.

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 setDetails(string n, int a) {


name = n;
age = a;
}

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;
}

Constant Member Functions


A constant member function does not modify any data members of the class. It is declared
with the const keyword at the end of the function declaration.

#include <iostream>
using namespace std;

class Car {
private:
string brand;

public:
Car(string b) { brand = b; }

void showBrand() const { // Constant function


cout << "Car Brand: " << brand << endl;
}
};
int main() {
Car car1("Toyota");
car1.showBrand(); // This will not modify any data members

return 0;
}

The showBrand() function is declared const.


Constant functions cannot modify class members.

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; }

void showRadius() const {


cout << "Radius: " << radius << endl;
}
};

int main() {
const Circle c1(5.5); // Constant object
c1.showRadius(); // Can only call constant member functions

// c1.radius = 10; // Error: Cannot modify constant object

return 0;
}

const Circle c1(5.5); creates a constant object.


Only constant member functions can be called on constant objects.

Memory Management in cpp


Yes, in C++, there are two memory management operators:

new → Allocates memory dynamically on the heap.


delete → Deallocates memory from the heap.
These operators allow us to manage memory manually, unlike stack-based memory, which
is automatically managed.

new Operator (Dynamic Memory Allocation)

Used to allocate memory on the heap.


Returns a pointer to the allocated memory.
Can be used for single variables and arrays.
Example:

#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

delete myCar; // Free the allocated memory


return 0;
}

new Car("Toyota"); dynamically allocates a Car object.


delete myCar; frees the allocated memory to prevent memory leaks.

delete Operator (Memory Deallocation)


Used to free memory allocated using new .
Prevents memory leaks.
Can be used for single objects and arrays.
Example:

#include <iostream>
using namespace std;

int main() {
int* arr = new int[5]; // Allocating an array of 5 integers

// Initializing and displaying values


for (int i = 0; i < 5; i++) {
arr[i] = i * 10;
cout << arr[i] << " ";
}

delete[] arr; // Freeing the allocated memory


return 0;
}

new int[5]; dynamically allocates an array of integers.


delete[] arr; deallocates the array to free memory.

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.

2 important properties of encapsulation


1. Data Protection: Encapsulation protects the internal state of an object by keeping its data
members private. Access to and modification of these data members is restricted to the
class’s public methods, ensuring controlled and secure data manipulation.
2. Information Hiding: Encapsulation hides the internal implementation details of a class from
external code. Only the public interface of the class is accessible, providing abstraction and
simplifying the usage of the class while allowing the internal implementation to be modified
without impacting external code.
Encapsulation also leads to data abstraction. Using encapsulation also hides the data, as in
the above example, the data of the sections like sales, finance, or accounts are hidden from
any other section.

Role of access specifiers in encapsulation


Access specifiers facilitate Data Hiding in C++ programs by restricting access to the class
member functions and data members. There are three types of access specifiers in C++:

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.

2 steps for encapsulation


1. Creating a class to encapsulate all the data and methods into a single unit.
2. Hiding relevant data using access specifiers.

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
};

class child_class: access_modifier parent_class {


//Body of child 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;
}
};

class Male : public Human {


public:
string color;

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:

class Male : protected Human {


public:
string color;

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:

class derived_class1: access_specifier base_class


{
... .. ...
}
class derived_class2: access_specifier derived_class1
{
... .. ...
}
.....
Example:

#include <iostream>
#include <string>
using namespace std;

class Animal{
public:
int age;
int weight;

void speak(){
cout<<"speaking"<<endl;
}
};

class Dog : public Animal {

};

class Labrador : public Dog {

};

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:

class __subclass_name__ : access_mode __base_class1__, access_mode


__base_class2__, ....
{
// __body of subclass__
};

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;
}

4. ### Hierarchical Inheritance


In this type of inheritance, more than one subclass is inherited from a single base class. i.e.
more than one derived class is created from a single base class.
Syntax:

class derived_class1: access_specifier base_class


{
... .. ...
}
class derived_class2: access_specifier base_class
{
... .. ...
}
Example:

#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;
}
};

class C: public A, public B {

};

int main() {

C obj;
//obj.func();

obj.A::func() ;
obj.B::func();

return 0;
}

Virtual base class


In multiple inheritance, a common issue arises when multiple base classes inherit from the
same grandparent class, leading to duplicate instances of the grandparent class in the derived
class. A virtual base class solves this by ensuring only one instance of the grandparent class
is present.
Example:

#include<iostream>
using namespace std;

class A {
public:
int x;
A() { x = 10; }
};

class B : virtual public A { }; // Virtual base class


class C : virtual public A { }; // Virtual base class

class D : public B, public C { };

int main() {
D obj;
cout << obj.x << endl; // No ambiguity
return 0;
}

Without virtual , class D would inherit two copies of A , leading to ambiguity.

Overriding Inheritance Methods


When a derived class provides its own version of a base class function, method overriding
occurs.
Example of overriding a function:

class Base {
public:
virtual void show() { cout << "Base class show()" << endl; }
};

class Derived : public Base {


public:
void show() override { cout << "Derived class show()" << endl; }
};
int main() {
Base* ptr;
Derived obj;
ptr = &obj;
ptr->show(); // Calls Derived class method due to virtual function
return 0;
}

Using virtual in the base class allows polymorphism, so calling show() on a Base* points
to the derived class method.

Constructors in derived classes


When a derived class is instantiated, base class constructors run first before the derived class
constructor.

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

class Derived : public Base {


public:
Derived() { cout << "Derived Constructor" << endl; }
};

int main() {
Derived obj;
return 0;
}

Output:

Base Constructor
Derived Constructor

The base class constructor is called first.

Abstraction
Read this
Abstraction and Encapsulation difference
Aggregation vs. Composition vs. Classification
Hierarchies
These describe relationship between classes.

(a) Aggregation ("Has-a" Relationship)

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(); }
};

(b) Composition (Strong Containment)

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(); }
};

(c) Classification Hierarchies

Generalization ("Is-a" Relationship) where a subclass inherits from a base class.


Example: A "Dog" is a "Mammal."

class Mammal {
public:
void breathe() { cout << "Breathing..." << endl; }
};

class Dog : public Mammal {


public:
void bark() { cout << "Barking..." << 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>

using namespace std;

/* start of Enclosing class declaration */


class Enclosing {
private:
int x;

/* start of Nested class declaration */


class Nested {
int y;
void NestedFun(Enclosing *e) {
cout<<e->x; // works fine: nested class can access
// private members of Enclosing class
}
}; // declaration Nested class ends here
}; // declaration Enclosing class ends here

int main()
{
}

Program 2:

#include<iostream>

using namespace std;

/* start of Enclosing class declaration */


class Enclosing {

int x;

/* start of Nested class declaration */


class Nested {
int y;
}; // declaration Nested class ends here

void EnclosingFun(Nested *n) {


cout<<n->y; // Compiler Error: y is private in Nested
}
}; // declaration Enclosing class ends here

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) {}

// Friend function declaration


friend void showX(A obj);
};

// Friend function definition


void showX(A obj) {
cout << "Value of x: " << obj.x << endl; // Accessing private member
}

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.

Runtime and compile time


Compile time
The phase where the source code is compiled into machine code.
Errors like syntax errors, type errors, and missing functions occur at compile-time.
Examples:
- Type mismatches
- Undefined variables
- Incorrect function calls
Example of compile time error:

#include <iostream>
using namespace std;

int main() {
int num = "Hello"; // ERROR: Type mismatch
cout << num << endl;
return 0;
}

Error: "Hello" is a string but is assigned to an int .

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;
}

Error: Division by zero causes a crash at runtime.

Stack vs. Heap Memory


Memory is divided into different sections:

1. Stack Memory (for static & local variables)


2. Heap Memory (for dynamically allocated memory)

(a) Stack Memory (Faster, Fixed Size)


Stores local variables, function calls, and return addresses.
Memory is automatically allocated and deallocated.
Limited in size.
Faster than heap memory.
Example of stack allocation:

#include <iostream>
using namespace std;

void myFunction() {
int x = 10; // Stored in stack
cout << x << endl;
}

int main() {
myFunction();
return 0;
}

Here, x is stored on the stack and removed once myFunction() finishes.


Key Points:

Stack memory is automatically managed.


Each function call gets its own stack frame.
When a function returns, the memory is freed automatically.

(b) Heap Memory (Slower, Flexible)


Used for dynamic memory allocation.
Memory is manually allocated and freed using new and delete .
Larger but slower than stack memory.
Example of heap allocation:

#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:

new int(20) allocates an int in heap memory.


delete ptr frees the allocated memory to prevent memory leaks.
Key Points:
Heap memory must be explicitly freed ( delete ).
Useful for large or flexible data structures (e.g., linked lists, trees).
Memory leaks occur if you forget to free allocated memory.

Common Memory Leak Issue:

void badFunction() {
int* ptr = new int(100);
// Forgot to delete ptr → Memory leak
}

Since delete ptr is missing, the allocated memory is never freed.

Comparison: Stack vs. Heap

Feature Stack Heap


Speed Faster Slower
Size Limit Small Large
Allocation Automatic Manual ( new )
Deallocation Automatic Manual ( delete )
Use Cases Local variables, function calls Dynamic memory (objects, arrays)

You might also like