0% found this document useful (0 votes)
2 views23 pages

BCS 31 3 Sesson Combo

The document outlines key concepts of Object-Oriented Programming (OOP) including access specifiers, abstraction, encapsulation, and message passing. It contrasts OOP with structured programming, highlighting advantages such as modularity, reusability, and maintainability. Additionally, it discusses constructors, copy constructors, and the significance of the 'this' pointer in class member functions.

Uploaded by

Samir Rajak
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)
2 views23 pages

BCS 31 3 Sesson Combo

The document outlines key concepts of Object-Oriented Programming (OOP) including access specifiers, abstraction, encapsulation, and message passing. It contrasts OOP with structured programming, highlighting advantages such as modularity, reusability, and maintainability. Additionally, it discusses constructors, copy constructors, and the significance of the 'this' pointer in class member functions.

Uploaded by

Samir Rajak
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/ 23

🧩 1.

OOP Concepts & Principles


Access Specifiers (public/protected/private) Access specifiers control the visibility and accessibility of
class members (data and functions).
• public: Members declared as public are accessible from anywhere, both within the class and from
outside the class. They form the interface of the class.
• protected: Members declared as protected are accessible within the class itself and by derived
classes. They are not accessible from outside the class directly.
• private: Members declared as private are only accessible from within the class they are declared
in. They are not accessible from outside the class, nor by derived classes. This is the strictest level
of access control.
Object-Oriented vs. Structured Programming – features, advantages
Feature/Aspect Structured Programming Object-Oriented Programming (OOP)
Paradigm Procedure-oriented, top-down approach Object-oriented, bottom-up approach
Functions, algorithms, and data as
Primary Focus Objects (data + functions combined)
separate entities
Strong support (encapsulation, access
Data Hiding Limited or no direct support
specifiers)
Modularity Achieved through functions Achieved through classes and objects
Achieved through inheritance, composition,
Reusability Achieved through function calls
and templates
Complexity Can become complex for large systems Manages complexity better for large systems
Flexibility Less flexible to changes More flexible and adaptable to changes
Real-world
Focus on "how to do" Focus on "what is" (real-world entities)
Model
Export to Sheets
Advantages of OOP:
• Modularity: Breaking down complex problems into smaller, manageable objects.
• Reusability: Code can be reused through inheritance and composition, reducing development time.
• Maintainability: Easier to debug and update code due to modularity and encapsulation.
• Scalability: Well-suited for large and complex systems.
• Flexibility: Easier to adapt to changing requirements.
• Data Security: Data hiding and encapsulation protect data from unauthorized access.
Abstraction – define with example Abstraction is the process of hiding the complex implementation
details and showing only the essential features of an object. It focuses on "what" an object does rather than
"how" it does it.
Example: Consider a car. When you drive a car, you interact with the steering wheel, accelerator, and
brakes. You don't need to know the intricate details of how the engine works, how the fuel mixes, or how
the braking system operates. The car's controls provide an abstraction of its underlying complexity.
In programming, an abstract class or interface can define a common interface without providing full
implementation.
C++
// Example of Abstraction using an Abstract Class
class Shape { // Abstract class
public:
virtual double area() = 0; // Pure virtual function
virtual void draw() = 0; // Pure virtual function
void displayInfo() { // Concrete method
// Common information display
std::cout << "This is a shape." << std::endl;
}
};

class Circle : public Shape {


private:

1
double radius;
public:
Circle(double r) : radius(r) {}
double area() override {
return 3.14159 * radius * radius;
}
void draw() override {
std::cout << "Drawing a Circle." << std::endl;
}
};

// In main, you interact with Shape objects without knowing their specific type
initially.
// Shape* s = new Circle(5.0);
// s->area(); // Abstraction at work

Encapsulation vs. Information Hiding


• Encapsulation: The bundling of data (attributes) and methods (functions) that operate on the data
into a single unit (class). It is the mechanism that binds together code and the data it manipulates.
Encapsulation also means that the internal state of an object is hidden from the outside world.
• Information Hiding: A principle of software design where the internal implementation details of a
class are hidden from the outside world. It is achieved through access specifiers (private, protected).
Information hiding is a consequence or outcome of effective encapsulation.
Relationship: Encapsulation is the technique (bundling, restricting access), and information hiding is the
goal or result (preventing direct access to internal data, exposing only what's necessary).
Message Passing – concept & example Message passing is the mechanism by which objects communicate
with each other. When one object wants another object to perform a task, it sends a "message" to that
object. In C++, message passing is typically achieved by calling a member function of an object. The
function call is the "message," and the parameters passed are the "arguments" of the message.
Example:
C++
class Account {
private:
double balance;
public:
Account(double initialBalance) : balance(initialBalance) {}

void deposit(double amount) { // deposit() is a message


if (amount > 0) {
balance += amount;
std::cout << "Deposited: " << amount << ". New balance: " << balance <<
std::endl;
}
}

void withdraw(double amount) { // withdraw() is another message


if (amount > 0 && balance >= amount) {
balance -= amount;
std::cout << "Withdrew: " << amount << ". New balance: " << balance <<
std::endl;
} else {
std::cout << "Insufficient balance or invalid amount." << std::endl;
}
}
};

// In main:
// Account myAccount(1000);
// myAccount.deposit(500); // Sending a "deposit" message to myAccount object
// myAccount.withdraw(200); // Sending a "withdraw" message to myAccount object

2
Abstract Class & Pure Virtual Functions – explanation and examples
• Abstract Class: A class that cannot be instantiated directly (you cannot create an object of an
abstract class). It is designed to be inherited by other classes. An abstract class typically contains at
least one pure virtual function. Its purpose is to provide a common interface for its derived classes.
• Pure Virtual Function: A virtual function declared by assigning 0 to its declaration, like virtual
returnType functionName() = 0;. A pure virtual function has no implementation in the base
class; its implementation must be provided by any concrete (non-abstract) derived class. If a
derived class fails to implement all pure virtual functions of its abstract base, it also becomes an
abstract class.
Example:
C++
class Animal { // Abstract Class
public:
virtual void makeSound() = 0; // Pure virtual function
virtual void sleep() { // Regular virtual function
std::cout << "Animal is sleeping." << std::endl;
}
};

class Dog : public Animal {


public:
void makeSound() override { // Must implement makeSound()
std::cout << "Woof!" << std::endl;
}
// sleep() can be overridden or inherited
};

class Cat : public Animal {


public:
void makeSound() override { // Must implement makeSound()
std::cout << "Meow!" << std::endl;
}
};

// In main:
// Animal* myDog = new Dog();
// myDog->makeSound(); // Calls Dog's makeSound()
// Animal* myCat = new Cat();
// myCat->makeSound(); // Calls Cat's makeSound()
// Animal anAnimal; // ERROR: Cannot instantiate abstract class

🔗 2. Functions & Binding


Inline Function – explain with example An inline function is a hint to the compiler that the function
should be expanded "in-line" at the point of its call, rather than being called through a regular function call
mechanism. This can reduce the overhead of function calls (especially for small, frequently called
functions) and potentially improve performance. The compiler may ignore the inline keyword if the
function is too large or complex.
Example:
C++
inline int add(int a, int b) {
return a + b;
}

// In main:
// int x = 5, y = 10;
// int sum = add(x, y); // Compiler might replace this with 'int sum = x + y;'
Friend Functions – purpose, encapsulation effects, vs. member functions
• Purpose: A friend function is a non-member function that is granted special permission to access
the private and protected members of a class. It is declared inside the class with the friend
keyword.

3
• Encapsulation Effects: Friend functions violate strict encapsulation. While encapsulation aims to
hide internal details, friend functions explicitly bypass this hiding. They should be used sparingly
and only when absolutely necessary, for example, for overloaded operators that need access to two
objects' private data (e.g., operator<< for stream insertion).
• Vs. Member Functions:
o Member Function: Operates on an object of the class, has an implicit this pointer, and can
access all members (public, protected, private) of that object.
o Friend Function: A standalone function that is not a part of the class, does not have a this
pointer, and is granted access to private/protected members explicitly by the class. It needs
an object of the class passed as an argument to access its members.
Example:
C++
class MyClass {
private:
int privateData;
public:
MyClass(int val) : privateData(val) {}
// Declaration of friend function
friend void showPrivateData(const MyClass& obj);
};

void showPrivateData(const MyClass& obj) {


// Friend function can access private members
std::cout << "Private data: " << obj.privateData << std::endl;
}

// In main:
// MyClass obj(100);
// showPrivateData(obj); // Friend function call
Virtual Functions – what they are, uses, vs. pure virtual
• Virtual Function: A member function in a base class that you expect to be redefined in derived
classes. When you call a virtual function through a pointer or reference to the base class, the version
of the function executed is determined at runtime based on the actual type of the object pointed to
or referenced (runtime polymorphism). Declared using the virtual keyword.
• Uses: Enable runtime polymorphism, allowing you to write generic code that operates on base class
pointers/references but behaves differently based on the specific derived object.
• Vs. Pure Virtual Function:
o Virtual Function: Has an implementation in the base class (though it can be empty).
Derived classes can optionally override it. A class with only virtual functions can be
instantiated.
o Pure Virtual Function: Has no implementation in the base class (= 0). Derived classes
must override it (unless they also become abstract). A class with at least one pure virtual
function is an abstract class and cannot be instantiated.
Example: (See "Abstract Class & Pure Virtual Functions" above for example)
Early (Static) vs. Late (Dynamic) Binding – differentiate with examples
• Early Binding (Static Binding/Compile-time Polymorphism): The function call resolution is
determined at compile time. This occurs for normal function calls, overloaded functions, and non-
virtual functions. The compiler knows exactly which function to call based on the type of the
object/pointer at compile time.
o Example: Function overloading.
• Late Binding (Dynamic Binding/Runtime Polymorphism): The function call resolution is
determined at runtime. This happens when you use virtual functions through base class pointers or
references. The actual function to be called depends on the type of the object pointed to or
referenced at the time of execution.

4

o Example: Virtual functions.
Example:
C++
class Base {
public:
void nonVirtualFunc() {
std::cout << "Base non-virtual function" << std::endl;
}
virtual void virtualFunc() {
std::cout << "Base virtual function" << std::endl;
}
};

class Derived : public Base {


public:
void nonVirtualFunc() {
std::cout << "Derived non-virtual function" << std::endl;
}
void virtualFunc() override {
std::cout << "Derived virtual function" << std::endl;
}
};

// In main:
// Base* ptr;
// Derived objD;
// ptr = &objD;

// Early Binding:
// ptr->nonVirtualFunc(); // Calls Base::nonVirtualFunc() because 'ptr' is of type
Base*

// Late Binding:
// ptr->virtualFunc(); // Calls Derived::virtualFunc() because the actual object is
Derived

Runtime Polymorphism – explain with example Runtime polymorphism (also known as dynamic
polymorphism or late binding) is the ability of an object to take on many forms at runtime. In C++, it is
achieved using virtual functions and base class pointers/references. When a virtual function is called
through a base class pointer or reference, the actual function executed is determined by the type of the
object being pointed to/referenced at runtime, not the type of the pointer/reference itself.
Example: (See "Virtual Functions" or "Early vs. Late Binding" examples, as they illustrate runtime
polymorphism directly).

🏗 3. Constructors & Special Members


Constructors – concept, four to five characteristics
• Concept: A constructor is a special member function of a class that is automatically invoked when
an object of that class is created. Its primary purpose is to initialize the object's data members.
• Characteristics:
1. Same Name as Class: A constructor must have the same name as the class it belongs to.
2. No Return Type: Constructors do not have a return type, not even void.
3. Automatic Invocation: They are called implicitly when an object is created.
4. Can be Overloaded: A class can have multiple constructors with different parameters
(constructor overloading).
5. Can be Private/Protected: Though less common, constructors can be declared private or
protected to control object creation (e.g., for singleton patterns or to prevent direct
instantiation).

5
6. Default Constructor: If no constructor is explicitly defined, the compiler provides a default
constructor (which is public, no-argument, and does nothing).
Copy Constructor – role and invoking cases
• Role: A copy constructor is a special constructor that is used to create a new object as a copy of an
existing object. It takes a reference to an object of the same class as its argument, typically a const
reference. Its signature is ClassName(const ClassName& obj).
• Invoking Cases:
1. When an object is initialized with another object of the same class: ClassName obj2 =
obj1; or ClassName obj2(obj1);
2. When an object is passed by value to a function: void func(ClassName obj) { ... }
func(obj1);
3. When a function returns an object by value: ClassName func() { ClassName obj;
return obj; } ClassName obj2 = func();
4. When an object is thrown or caught as an exception.
Example:
C++
class MyData {
private:
int* data;
public:
MyData(int val) {
data = new int(val);
std::cout << "Constructor called, data: " << *data << std::endl;
}
// Copy Constructor
MyData(const MyData& other) {
data = new int(*other.data); // Deep copy
std::cout << "Copy Constructor called, data: " << *data << std::endl;
}
~MyData() {
delete data;
std::cout << "Destructor called" << std::endl;
}
void setData(int val) { *data = val; }
int getData() const { return *data; }
};

// In main:
// MyData obj1(10); // Constructor
// MyData obj2 = obj1; // Copy Constructor (initialization)
// MyData obj3(obj1); // Copy Constructor (initialization)

// void process(MyData m) { /* ... */ }


// process(obj1); // Copy Constructor (pass by value)

Default vs. Copy Constructor – differentiate with examples


• Default Constructor:
o A constructor that takes no arguments.
o If you don't provide any constructor for your class, the compiler automatically provides a
public default constructor.
o Used when an object is created without any initial values.
o Example: ClassName obj;
• Copy Constructor:
o A constructor that takes an object of the same class as an argument (usually a const
reference).
o Used to create a new object as a copy of an existing object.
o The compiler provides a default copy constructor if you don't define one, which performs a
member-wise (shallow) copy.
o Example: ClassName obj2 = obj1; or ClassName obj2(obj1);

6
Example: (See "Copy Constructor" for examples of copy constructor usage. For default: class MyClass
{ public: int x; MyClass() { x = 0; } }; MyClass obj;)
this pointer – significance and sample program
• Significance: The this pointer is a special pointer available inside every non-static member
function of a class. It points to the object on which the member function was called. It's implicitly
passed as a hidden argument to non-static member functions.
o It allows member functions to access the object's own members (distinguishing them from
local variables).
o It's used to return the current object from a member function (e.g., for chaining method
calls).
o It's crucial in operator overloading when an operator needs to return a reference to the
current object.
• Sample Program:
C++
class Point {
private:
int x, y;
public:
Point(int x = 0, int y = 0) : x(x), y(y) {}

void setX(int x) {
this->x = x; // 'this->x' refers to the member variable, 'x' refers to
the parameter
}

Point& moveBy(int dx, int dy) {


this->x += dx;
this->y += dy;
return *this; // Returns a reference to the current object
}

void display() const {


std::cout << "Point: (" << x << ", " << y << ")" << std::endl;
}
};

// In main:
// Point p(10, 20);
// p.display();
// p.setX(15);
// p.display();
// p.moveBy(5, 5).display(); // Chaining calls using 'this' pointer

Static Data Members/Functions – characteristics & use


• Static Data Members:
o Belong to the class itself, not to any specific object of the class.
o There is only one copy of a static data member for the entire class, shared by all objects.
o Initialized outside the class definition, typically in the .cpp file.
o Accessed using the class name and the scope resolution operator
(ClassName::staticMember).
o Useful for storing common data for all objects or counting objects.
• Static Member Functions:
o Can be called without creating an object of the class (using
ClassName::staticFunction()).
o Can only access static data members and other static member functions of the same class.
o Cannot access non-static data members or non-static member functions directly because
they don't have a this pointer (they are not associated with a specific object).
o Useful for utility functions that don't depend on object-specific data.

7
Example:
C++
class Counter {
private:
static int count; // Static data member declaration
public:
Counter() {
count++;
}
~Counter() {
count--;
}
static int getCount() { // Static member function
return count;
}
};

int Counter::count = 0; // Static data member definition and initialization

// In main:
// std::cout << "Initial count: " << Counter::getCount() << std::endl;
// Counter obj1;
// Counter obj2;
// std::cout << "Count after creating obj1, obj2: " << Counter::getCount() <<
std::endl;
// {
// Counter obj3;
// std::cout << "Count after creating obj3: " << Counter::getCount() << std::endl;
// } // obj3 goes out of scope, destructor called
// std::cout << "Count after obj3 destroyed: " << Counter::getCount() << std::endl;

Private Constructors/Destructors – explain differences


• Private Constructors:
o A constructor declared as private.
o Purpose: Prevents direct instantiation of a class from outside the class. This is commonly
used in:
§ Singleton Pattern: Ensures that only one instance of a class can be created. The
class itself typically provides a static public method to get the single instance.
§ Factory Methods: Forces object creation through specific static "factory" methods
within the class, allowing more control over object creation.
• Private Destructors:
o A destructor declared as private.
o Purpose: Prevents objects of the class from being deleted using delete or from being
created on the stack (i.e., it forces objects to be created on the heap and managed in a
specific way, often through smart pointers or by the class itself).
o This is less common than private constructors but can be used for classes that manage their
own memory or resources very carefully, preventing accidental deletion. It often implies
that a static destroy() method is provided.
Example (Private Constructor - Singleton):
C++
class Singleton {
private:
static Singleton* instance;
// Private constructor
Singleton() {
std::cout << "Singleton instance created!" << std::endl;
}
public:
// Static method to get the instance
static Singleton* getInstance() {
if (instance == nullptr) {

8
instance = new Singleton();
}
return instance;
}
// Delete copy constructor and assignment operator to prevent copying
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};

Singleton* Singleton::instance = nullptr; // Initialize static pointer

// In main:
// Singleton* s1 = Singleton::getInstance();
// Singleton* s2 = Singleton::getInstance();
// std::cout << (s1 == s2 ? "Same instance" : "Different instances") << std::endl;
// Singleton s3; // ERROR: private constructor

🧰 4. Operators & Templates


Stream Manipulators – e.g., setw(), setprecision(), others Stream manipulators are functions that
can be inserted into a stream (like std::cout or std::cin) to modify its formatting behavior. They are
found in the <iomanip> header.
• std::setw(int width): Sets the minimum field width for the next output operation. The output
is right-justified by default.
• std::setprecision(int precision): Sets the floating-point precision. For std::fixed or
std::scientific, it defines the number of digits after the decimal point. Otherwise, it defines the
total number of significant digits.
• std::fixed: Sets the floating-point output format to fixed-point notation (e.g., 123.456).
• std::scientific: Sets the floating-point output format to scientific notation (e.g., 1.23e+02).
• std::endl: Inserts a newline character and flushes the output buffer.
• std::flush: Flushes the output buffer.
• std::boolalpha / std::noboolalpha: Displays bool values as true/false strings or as 1/0,
respectively.
• std::left / std::right / std::internal: Sets the justification for output.
• std::dec / std::oct / std::hex: Sets the integer base for output (decimal, octal, hexadecimal).
Example:
C++
#include <iostream>
#include <iomanip> // Required for setw, setprecision, etc.

// In main:
// double pi = 3.1415926535;
// std::cout << "Default: " << pi << std::endl;
// std::cout << std::fixed << std::setprecision(2) << "Fixed 2: " << pi << std::endl;
// std::cout << std::scientific << std::setprecision(4) << "Scientific 4: " << pi <<
std::endl;

// int num = 123;


// std::cout << std::setw(10) << std::right << num << std::endl; // Right-justified
// std::cout << std::setw(10) << std::left << num << std::endl; // Left-justified

// bool flag = true;


// std::cout << std::boolalpha << flag << std::endl;
// std::cout << std::noboolalpha << flag << std::endl;

Operator Precedence – explain order & example Operator precedence determines the order in which
operators are evaluated in an expression. Operators with higher precedence are evaluated before operators
with lower precedence. If operators have the same precedence, their associativity (left-to-right or right-to-
left) determines the evaluation order.

9
General Order (Highest to Lowest, simplified):
1. Postfix: () [] . -> ++ -- (postfix)
2. Unary: + - ! ~ ++ -- (prefix) (type) * & sizeof
3. Multiplicative: * / %
4. Additive: + -
5. Shift: << >>
6. Relational: < <= > >=
7. Equality: == !=
8. Bitwise AND: &
9. Bitwise XOR: ^
10. Bitwise OR: |
11. Logical AND: &&
12. Logical OR: ||
13. Conditional (Ternary): ?:
14. Assignment: = += -= *= /= %= etc.
15. Comma: ,
Example: int result = 5 + 3 * 2;
• * has higher precedence than +.
• So, 3 * 2 is evaluated first (result 6).
• Then, 5 + 6 is evaluated (result 11).
int x = 10; int y = 20; bool b = x > 5 && y < 15;
• > and < have higher precedence than &&.
• x > 5 (true) and y < 15 (false) are evaluated first.
• Then true && false is evaluated (result false).
Function Overloading vs. Overriding – explain with code
• Function Overloading:
o Concept: Defining multiple functions in the same scope (e.g., within the same class or
globally) with the same name but different parameter lists (different number of parameters,
different types of parameters, or different order of parameter types). The compiler selects
the correct function based on the arguments passed during the call.
o Binding: Achieved through early (static) binding at compile time.
o Relationship: No inheritance required.
o Example:
C++
class Calculator {
public:
int add(int a, int b) {
return a + b;
}
double add(double a, double b) { // Overloaded function
return a + b;
}
int add(int a, int b, int c) { // Another overloaded function
return a + b + c;
}
};
// In main:
// Calculator calc;
// calc.add(5, 10); // Calls int add(int, int)
// calc.add(5.5, 10.2); // Calls double add(double, double)

10
• Function Overriding:
o Concept: Redefining a base class's virtual member function in a derived class. The
function in the derived class must have the same name, same return type, and same
parameter list as the base class's virtual function. The override keyword (C++11+) is good
practice.
o Binding: Achieved through late (dynamic) binding at runtime (when called via a base
class pointer/reference).
o Relationship: Requires inheritance and virtual functions.
o Example:
C++
class Base {
public:
virtual void show() { // Virtual function
std::cout << "Base class show()" << std::endl;
}
};

class Derived : public Base {


public:
void show() override { // Overriding base class show()
std::cout << "Derived class show()" << std::endl;
}
};
// In main:
// Base* bPtr;
// Derived dObj;
// bPtr = &dObj;
// bPtr->show(); // Calls Derived::show() due to runtime polymorphism

Operator Overloading (e.g., + for complex numbers)


• Concept: Operator overloading allows you to redefine the behavior of existing C++ operators when
applied to user-defined types (classes). It makes code more intuitive and readable, allowing
operators to work with objects in a natural way. You cannot create new operators or change the
precedence/associativity of existing ones.
• Example (overloading + for Complex numbers):
C++
class Complex {
private:
double real;
double imag;
public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}

// Overload the + operator as a member function


Complex operator+(const Complex& other) const {
return Complex(real + other.real, imag + other.imag);
}

void display() const {


std::cout << real << " + " << imag << "i" << std::endl;
}
};

// In main:
// Complex c1(3.0, 4.0);
// Complex c2(1.5, 2.5);
// Complex c3 = c1 + c2; // Calls c1.operator+(c2)
// c3.display(); // Output: 4.5 + 6.5i

11
Templates: class templates (stack, linked list), advantages
• Concept: Templates are a powerful feature in C++ that allow you to write generic programming.
They enable you to define functions or classes that operate with generic types, without specifying
the exact data types beforehand. The actual types are passed as arguments at compile time.
• Class Templates: Define a blueprint for a class where one or more data types or values are
parameterized. This allows you to create classes that can work with any data type.
o Example (Stack Class Template):
C++
template <typename T> // 'T' is a template type parameter
class Stack {
private:
T* arr;
int top;
int capacity;
public:
Stack(int size) : capacity(size), top(-1) {
arr = new T[capacity];
}
~Stack() { delete[] arr; }

void push(T val) {


if (top < capacity - 1) {
arr[++top] = val;
} else {
std::cout << "Stack overflow!" << std::endl;
}
}
T pop() {
if (top >= 0) {
return arr[top--];
}
std::cout << "Stack underflow!" << std::endl;
return T(); // Return default value for type T
}
// ... other stack operations
};

// In main:
// Stack<int> intStack(5);
// intStack.push(10);
// intStack.push(20);
// std::cout << intStack.pop() << std::endl; // Output: 20

// Stack<std::string> stringStack(3);
// stringStack.push("Hello");
// stringStack.push("World");
// std::cout << stringStack.pop() << std::endl; // Output: World
• Advantages of Templates:
1. Code Reusability: Write a single code once and use it for various data types, reducing
redundant code.
2. Type Safety: Templates provide compile-time type checking, which helps catch type errors
early.
3. Efficiency: Generated code is as efficient as specialized code because the type is known at
compile time.
4. Genericity: Allows creation of generic data structures (like std::vector, std::list,
std::map) and algorithms that work with different types.

12
🧩 5. Classes & Inheritance
Difference between Class & Object
• Class:
o A blueprint or template for creating objects.
o It defines the attributes (data members) and behaviors (member functions) that objects of
that type will possess.
o It's a logical entity; it doesn't occupy memory directly when defined.
• Object:
o An instance of a class.
o A real-world entity that has state (values for its attributes) and behavior.
o It's a physical entity; it occupies memory when created.
Analogy: A class is like a cookie cutter (the design), and an object is like a cookie (an actual instance
created using the design).
Member vs. Global Functions – explain
• Member Functions:
o Declared inside a class and operate on the data members of objects of that class.
o They are invoked using an object (e.g., object.memberFunction()).
o They have access to all members (public, protected, private) of the object they are called on,
including the this pointer.
o They define the behavior specific to an object of the class.
• Global Functions:
o Declared outside any class, in the global scope.
o They are standalone functions and do not belong to any particular object.
o They are invoked directly by their name (e.g., globalFunction()).
o They can only access global variables and the public members of objects if an object is
passed as an argument. They cannot directly access private or protected members of a class
unless declared as friend.
o They perform operations that are not inherently tied to the state or behavior of a single
object.
Protected vs. Public Access – usage
• public Access:
o Usage: Used for members that form the external interface of the class. Any code outside the
class can directly access public members.
o Purpose: To provide services and data that users of the class are intended to interact with.
o Example: Member functions that represent actions (deposit(), withdraw()), or data that
is meant to be directly accessed (less common, usually via getters/setters).
• protected Access:
o Usage: Used for members that are intended to be accessible by the class itself and by its
derived classes, but not directly by objects outside the inheritance hierarchy.
o Purpose: To facilitate inheritance and allow derived classes to extend or modify the base
class's behavior while still maintaining some level of encapsulation from external users. It's
often used for internal data or helper functions that derived classes need to work with.
o Example: A base class Vehicle might have a protected engineStatus variable that Car
and Motorcycle (derived classes) can access to implement their specific behaviors, but a
random function cannot directly change engineStatus of a Vehicle object.
Inheritance – definition, types, implementation
• Definition: Inheritance is a fundamental OOP concept that allows a new class (the "derived" or
"child" class) to inherit properties (data members) and behaviors (member functions) from an
existing class (the "base" or "parent" class). This promotes code reusability and establishes an "is-a"
relationship between classes.

13

• Types of Inheritance:
1. Single Inheritance: A derived class inherits from only one base class.
§ class Derived : public Base { ... };
2. Multiple Inheritance: A derived class inherits from multiple base classes.
§ class Derived : public Base1, public Base2 { ... };
3. Multilevel Inheritance: A class inherits from a derived class, forming a chain. (e.g., A -> B
-> C)
§ class B : public A { ... }; class C : public B { ... };
4. Hierarchical Inheritance: Multiple derived classes inherit from a single base class.
§ class B : public A { ... }; class C : public A { ... };
5. Hybrid (Multipath) Inheritance: A combination of two or more types of inheritance (e.g.,
multiple and hierarchical), often leading to the "diamond problem" (solved with virtual
inheritance).
• Implementation: Inheritance is implemented using the colon (:) followed by the access specifier
(public, protected, or private) and the base class name in the derived class definition. The
access specifier determines how the base class's members' access levels are adjusted in the derived
class.
Example (Single Inheritance):
C++
class Animal { // Base Class
public:
void eat() {
std::cout << "Animal is eating." << std::endl;
}
void sleep() {
std::cout << "Animal is sleeping." << std::endl;
}
};

class Dog : public Animal { // Derived Class (public inheritance)


public:
void bark() {
std::cout << "Dog is barking." << std::endl;
}
};

// In main:
// Dog myDog;
// myDog.eat(); // Inherited from Animal
// myDog.sleep(); // Inherited from Animal
// myDog.bark(); // Specific to Dog
Multilevel vs. Multiple Inheritance
• Multilevel Inheritance:
o Structure: A linear chain of inheritance: Class A -> Class B -> Class C.
o Relationship: Class B inherits from A, and Class C inherits from B. This means C
implicitly inherits from A through B.
o Purpose: Extends functionality progressively.
o Example: Vehicle -> Car -> SportsCar
• Multiple Inheritance:
o Structure: A class inherits directly from two or more base classes.
o Relationship: Class C inherits from Class A and Class B simultaneously.
o Purpose: Combines functionalities from distinct sources into a single derived class.
o Problem: Can lead to the "diamond problem" (ambiguity if a common base class is
inherited through multiple paths), often resolved using virtual inheritance.
o Example: FlyingCar could inherit from Car and Aircraft.

14
🗄 6. File & Streams
Concept of Streams – types used in file I/O
• Concept of Streams: A stream is an abstraction that represents a sequence of bytes. It acts as an
interface to input/output devices. Data flows into (input stream) or out of (output stream) the
program through these streams. This abstraction allows handling diverse I/O devices (files,
keyboard, screen, network) in a uniform manner.
• Types used in File I/O (from <fstream>):
o std::fstream: General-purpose stream for both input and output to files. Can open files for
reading, writing, or both.
o std::ifstream: Input file stream. Used specifically for reading data from files.
o std::ofstream: Output file stream. Used specifically for writing data to files.
Example (basic usage):
C++
#include <iostream>
#include <fstream>
#include <string>

// In main:
// // Writing to a file
// std::ofstream outFile("example.txt");
// if (outFile.is_open()) {
// outFile << "Hello, File I/O!" << std::endl;
// outFile << "This is a new line." << std::endl;
// outFile.close();
// std::cout << "Data written to example.txt" << std::endl;
// } else {
// std::cerr << "Unable to open file for writing." << std::endl;
// }

// // Reading from a file


// std::ifstream inFile("example.txt");
// if (inFile.is_open()) {
// std::string line;
// while (std::getline(inFile, line)) {
// std::cout << "Read: " << line << std::endl;
// }
// inFile.close();
// } else {
// std::cerr << "Unable to open file for reading." << std::endl;
// }
Program: append text to existing file To append text to an existing file, you open the ofstream or
fstream object in std::ios::app mode (append mode).
C++
#include <iostream>
#include <fstream>
#include <string>

int main() {
std::string textToAppend = "\nThis text is appended.\n";

// Open file in append mode


std::ofstream outFile("my_log.txt", std::ios::app);

if (outFile.is_open()) {
outFile << textToAppend;
outFile.close();
std::cout << "Text appended to my_log.txt" << std::endl;

// Optionally, read and display the content to verify


std::ifstream inFile("my_log.txt");
if (inFile.is_open()) {

15
std::string line;
std::cout << "\nContent of my_log.txt after appending:" << std::endl;
while (std::getline(inFile, line)) {
std::cout << line << std::endl;
}
inFile.close();
} else {
std::cerr << "Error reading file after append." << std::endl;
}
} else {
std::cerr << "Unable to open file for appending." << std::endl;
}

return 0;
}

istream/ostream – demonstrate queue operations While istream and ostream are generic input/output
streams, they aren't directly used for queue operations in the data structure sense. However, they can be
used to simulate queue-like behavior when dealing with data flow, such as reading input sequentially (like
dequeuing) and writing output sequentially (like enqueuing). The question might be referring to
demonstrating basic I/O operations that mimic flow rather than implementing a full queue data structure
using streams.
Let's assume it means demonstrating sequential input/output similar to how a queue processes elements.
C++
#include <iostream>
#include <queue> // For a real queue data structure
#include <string>

// Demonstrate sequential input/output (mimicking queue flow)


void processStreamQueue() {
std::cout << "Enter items for the 'input queue' (type 'done' to finish):" <<
std::endl;
std::string inputItem;
// Simulating enqueueing into an input stream
std::string allInput;
while (std::getline(std::cin, inputItem) && inputItem != "done") {
allInput += inputItem + "\n";
}

std::cout << "\nProcessing items from 'input queue' (reading):" << std::endl;
// Simulating dequeuing from an input stream
std::istringstream inputStream(allInput); // Treat allInput as an input stream
std::string processedItem;
while (std::getline(inputStream, processedItem, '\n')) { // Read line by line
(dequeue)
std::cout << "Processed: " << processedItem << std::endl;
}

std::cout << "\nAdding items to 'output queue' (writing):" << std::endl;


std::ostringstream outputStream; // Treat as an output stream
outputStream << "First item for output\n"; // Enqueue to output
outputStream << "Second item for output\n";
outputStream << "Third item for output\n";

std::cout << "Contents of 'output queue' (retrieved from stream):" << std::endl;
std::cout << outputStream.str(); // Retrieve full output string
}

// Actual queue operations using std::queue and displaying via streams


void demonstrateStdQueue() {
std::queue<std::string> myQueue;

std::cout << "\n--- Demonstrating std::queue ---" << std::endl;

16
// Enqueue operations
std::cout << "Enqueuing: Apple, Banana, Cherry" << std::endl;
myQueue.push("Apple");
myQueue.push("Banana");
myQueue.push("Cherry");

// Display front and size


std::cout << "Front element: " << myQueue.front() << std::endl;
std::cout << "Queue size: " << myQueue.size() << std::endl;

// Dequeue operations
std::cout << "Dequeuing elements:" << std::endl;
while (!myQueue.empty()) {
std::cout << "Dequeued: " << myQueue.front() << std::endl;
myQueue.pop();
}
std::cout << "Queue size after dequeuing: " << myQueue.size() << std::endl;
}

int main() {
processStreamQueue();
demonstrateStdQueue();
return 0;
}
Note: The first part processStreamQueue directly uses istream (std::cin and std::istringstream)
and ostream (std::cout and std::ostringstream) to show data flow akin to queue operations. The
second part demonstrateStdQueue shows how a real queue data structure (std::queue) would use these
streams to output its operations.

🔄 7. Memory & Exception Handling


Call by Value vs. Call by Reference These are two fundamental ways to pass arguments to functions.
• Call by Value:
o Mechanism: A copy of the actual argument's value is passed to the function's formal
parameter.
o Effect on Original: Changes made to the parameter inside the function do not affect the
original argument in the calling function because the function operates on a separate copy.
o Memory: Requires extra memory for the copy.
o Use Case: When you want to preserve the original value of the argument and the function
doesn't need to modify it.
o Example:
C++
void incrementByValue(int x) {
x = x + 1;
std::cout << "Inside func (by value): " << x << std::endl;
}
// int num = 10;
// incrementByValue(num);
// std::cout << "Outside func: " << num << std::endl; // num is still 10
• Call by Reference:
o Mechanism: An alias (reference) to the actual argument is passed to the function's formal
parameter. The function directly works with the original memory location of the argument.
o Effect on Original: Changes made to the parameter inside the function do affect the
original argument in the calling function.
o Memory: No extra memory for a copy (only for the reference, which is typically an
address). More efficient for large objects.
o Use Case: When you need the function to modify the original argument, or when passing
large objects efficiently to avoid copying.
o Example:
C++

17
void incrementByReference(int& x) {
x = x + 1;
std::cout << "Inside func (by reference): " << x << std::endl;
}
// int num = 10;
// incrementByReference(num);
// std::cout << "Outside func: " << num << std::endl; // num is now 11
Dynamic Binding Association with Runtime Polymorphism
• Relationship: Dynamic binding (also known as late binding) is the mechanism that enables runtime
polymorphism.
• Explanation: When you have a base class pointer or reference pointing to a derived class object,
and you call a virtual function using that pointer/reference, the C++ runtime system uses dynamic
binding to determine which version of the virtual function (base or derived) to execute. It looks at
the actual type of the object at runtime, not the declared type of the pointer/reference at compile
time. This allows for flexible and extensible code where the behavior can vary based on the actual
object type at runtime.
Example: (See "Virtual Functions" or "Early vs. Late Binding" above for examples that illustrate this
association.)
new and delete operators – explanation
• new operator:
o Purpose: Used for dynamic memory allocation. It allocates memory on the heap (free store)
for an object or an array of objects.
o Behavior:
1. Allocates raw memory for the object(s).
2. Calls the constructor(s) for the object(s) to initialize them.
3. Returns a pointer to the newly allocated and constructed object(s).
o Syntax: pointer_variable = new Type; or pointer_variable = new Type[size];
• delete operator:
o Purpose: Used for dynamic memory deallocation. It frees memory previously allocated
with new.
o Behavior:
1. Calls the destructor(s) for the object(s) to perform any necessary cleanup.
2. Deallocates the raw memory.
o Syntax: delete pointer_variable; or delete[] pointer_variable; (for arrays)
o Crucial: It's vital to pair new with delete and new[] with delete[] to prevent memory
leaks.
Example:
C++
// In main:
// // Allocate single object
// int* ptrInt = new int;
// *ptrInt = 100;
// std::cout << "Dynamically allocated int: " << *ptrInt << std::endl;
// delete ptrInt; // Deallocate single object

// // Allocate array of objects


// int* arr = new int[5];
// for (int i = 0; i < 5; ++i) {
// arr[i] = (i + 1) * 10;
// }
// std::cout << "Dynamically allocated array: ";
// for (int i = 0; i < 5; ++i) {
// std::cout << arr[i] << " ";
// }
// std::cout << std::endl;
// delete[] arr; // Deallocate array
Exception – what it is, purpose, handling with example

18
•What it is: An exception is an abnormal event or error condition that occurs during the execution
of a program, disrupting the normal flow of instructions. Examples include division by zero, out-of-
memory errors, file not found, or invalid input.
• Purpose: Exception handling provides a structured and robust way to deal with runtime errors
without terminating the program abruptly. It separates error-handling code from normal program
logic, making the code cleaner and easier to maintain.
• Handling (using try, catch, throw):
o try block: Contains the code that might throw an exception.
o throw statement: Used to signal that an error has occurred. It "throws" an exception object
(of any type, e.g., int, string, std::exception derived class).
o catch block: Catches the thrown exception. It specifies the type of exception it can handle.
If an exception's type matches the catch block's parameter, that block is executed. Multiple
catch blocks can be used for different exception types.
Example:
C++
#include <iostream>
#include <string>
#include <stdexcept> // For std::runtime_error

double divide(double numerator, double denominator) {


if (denominator == 0) {
throw std::runtime_error("Error: Division by zero is not allowed!"); // Throw
an exception
}
return numerator / denominator;
}

int main() {
try {
double result1 = divide(10.0, 2.0);
std::cout << "10 / 2 = " << result1 << std::endl;

double result2 = divide(5.0, 0.0); // This will throw an exception


std::cout << "This line will not be executed." << std::endl;
}
catch (const std::runtime_error& e) { // Catch block for std::runtime_error
std::cerr << "Caught exception: " << e.what() << std::endl;
}
catch (const std::exception& e) { // Generic catch for other standard exceptions
std::cerr << "Caught generic exception: " << e.what() << std::endl;
}
catch (...) { // Catch-all block for any unhandled exception type
std::cerr << "Caught an unknown exception!" << std::endl;
}

std::cout << "Program continues after exception handling." << std::endl;


return 0;
}

🟨 8. Miscellaneous
Recursion – define and example
• Definition: Recursion is a programming technique where a function calls itself, either directly or
indirectly, to solve a problem. A recursive function solves a problem by breaking it down into
smaller, similar subproblems until it reaches a base case, which can be solved directly without
further recursion.
• Key Components:
1. Base Case: A condition that stops the recursion. Without it, the function would call itself
indefinitely, leading to a stack overflow.

19
2. Recursive Step: The part where the function calls itself with a modified input that moves
closer to the base case.
• Example (Factorial):
C++
int factorial(int n) {
// Base case: factorial of 0 or 1 is 1
if (n == 0 || n == 1) {
return 1;
}
// Recursive step: n * factorial of (n-1)
else {
return n * factorial(n - 1);
}
}

// In main:
// std::cout << "Factorial of 5: " << factorial(5) << std::endl; // Output: 120
Relational Operators – short note Relational operators are binary operators used to compare two
operands and determine their relationship. They always return a boolean value (true or false).
• Operators:
o == (Equal to)
o != (Not equal to)
o > (Greater than)
o < (Less than)
o >= (Greater than or equal to)
o <= (Less than or equal to)
• Use: Commonly used in conditional statements (if, while, for) to control program flow based on
comparisons.
• Example:
C++
int a = 10, b = 20;
std::cout << (a == b) << std::endl; // false (0)
std::cout << (a != b) << std::endl; // true (1)
std::cout << (a < b) << std::endl; // true (1)
Keywords vs. Identifiers – differentiate
• Keywords:
o Definition: Reserved words in the C++ language that have a predefined meaning to the
compiler.
o Usage: Cannot be used as names for variables, functions, classes, or any other user-defined
entities.
o Examples: int, float, class, public, private, if, else, while, for, return, new,
delete, virtual, this, template, typename, static, etc.
• Identifiers:
o Definition: Names given to various program elements by the programmer to identify them
uniquely.
o Usage: Used for naming variables, functions, classes, objects, namespaces, etc.
o Rules for Identifiers:
§ Can contain letters (A-Z, a-z), digits (0-9), and underscore (_).
§ Must start with a letter or an underscore (cannot start with a digit).
§ Case-sensitive (e.g., myVar is different from MyVar).
§ Cannot be a keyword.
§ Cannot contain spaces.
o Examples: myVariable, calculateSum, StudentClass, _temp, total_count.
Binary File vs. Text File, get() vs. getline()
• Binary File vs. Text File:
o Text File:
§ Stores data as sequences of characters (human-readable).

20
§Uses specific character encodings (e.g., ASCII, UTF-8).
§Data is often delimited by newline characters (\n).
§Platform-dependent newline characters (\r\n on Windows, \n on Unix) are handled
by the I/O system, potentially adding or removing characters during read/write.
§ Good for human-readable data, configuration files.
o Binary File:
§ Stores data as raw bytes, exactly as it is stored in memory.
§ Not directly human-readable.
§ No translation or interpretation of characters occurs during I/O.
§ Typically faster for large amounts of data and for storing structured data (objects,
images, etc.).
§ Good for program data, images, executables.
• get() vs. getline() (for std::istream):
o std::cin.get():
§ Purpose: Reads a single character from the input stream.
§ Behavior:
§ Can read any character, including whitespace (spaces, tabs, newlines).
§ Leaves the delimiter (e.g., newline) in the input buffer.
§ Overloads: Can also read a specified number of characters into a character array
until a delimiter is found or the limit is reached.
§ Return: Returns the character read (as an int), or EOF on failure.
o std::getline(stream, string_variable, delimiter):
§ Purpose: Reads an entire line from the input stream (or until a specified delimiter is
encountered) into a std::string object.
§ Behavior:
§ Reads characters until the delimiter is found or the end of the file is reached.
§ Extracts and discards the delimiter from the input buffer.
§ If no delimiter is specified, it defaults to newline (\n).
§ Return: Returns a reference to the istream object, which can be used in boolean
contexts to check for success.
Example:
C++
#include <iostream>
#include <string>
#include <fstream> // For file I/O

// int main() {
// // Demonstrate get()
// char c;
// std::cout << "Enter a character: ";
// c = std::cin.get();
// std::cout << "You entered (get): '" << c << "'\n";
// c = std::cin.get(); // Reads the leftover newline character
// std::cout << "Next char (get): '" << c << "'\n";

// // Demonstrate getline()
// std::string line;
// std::cout << "Enter a line: ";
// std::getline(std::cin, line); // Reads the whole line, discards newline
// std::cout << "You entered (getline): \"" << line << "\"\n";

// return 0;
// }
Strings in C++ – how handled, revision program In C++, strings are primarily handled using the
std::string class, which is part of the Standard Library (<string> header). This class provides a robust
and convenient way to work with sequences of characters, overcoming many limitations of C-style
character arrays (char*).

21
• How Handled by std::string:
o Dynamic Sizing: std::string objects can grow or shrink dynamically as needed,
managing their own memory.
o Automatic Memory Management: You don't need to manually allocate or deallocate
memory (no new/delete).
o Rich Set of Member Functions: Provides methods for concatenation (+, append()),
comparison (==, <, compare()), searching (find()), substring extraction (substr()),
length (length(), size()), iteration, and more.
o Built-in Operators: Supports overloaded operators for common string operations like
concatenation, assignment, and comparison.
o Conversion to C-style String: Can be converted to a null-terminated C-style string using
c_str() when interoperating with C functions.
o Efficiency: Highly optimized for various string manipulations.
Revision Program:
C++
#include <iostream>
#include <string> // Required for std::string

int main() {
// 1. Declaration and Initialization
std::string s1 = "Hello";
std::string s2("World");
std::string s3; // Empty string

// 2. Assignment
s3 = s1;
std::cout << "s3 after assignment from s1: " << s3 << std::endl;

// 3. Concatenation
std::string fullString = s1 + ", " + s2 + "!";
std::cout << "Concatenated string: " << fullString << std::endl;

// 4. Appending characters/strings
fullString.append(" How are you?");
std::cout << "After append: " << fullString << std::endl;
fullString += " Fine.";
std::cout << "After += : " << fullString << std::endl;

// 5. Length and Size


std::cout << "Length of fullString: " << fullString.length() << std::endl; // or
fullString.size()

// 6. Accessing characters (like an array)


std::cout << "First character: " << fullString[0] << std::endl;
std::cout << "Last character: " << fullString[fullString.length() - 1] <<
std::endl;

// 7. Comparison
if (s1 == "Hello") {
std::cout << "s1 is 'Hello'." << std::endl;
}
if (s1 != s2) {
std::cout << "s1 and s2 are different." << std::endl;
}

// 8. Substring
std::string sub = fullString.substr(7, 5); // Start at index 7, length 5
std::cout << "Substring from fullString: " << sub << std::endl; // Output: World

// 9. Searching
size_t pos = fullString.find("World");
if (pos != std::string::npos) {

22
std::cout << "'World' found at position: " << pos << std::endl;
} else {
std::cout << "'World' not found." << std::endl;
}

// 10. Input from user


std::string userName;
std::cout << "Enter your name: ";
std::getline(std::cin, userName); // Reads entire line including spaces
std::cout << "Hello, " << userName << "!" << std::endl;

// 11. Clear a string


s3.clear();
std::cout << "Is s3 empty? " << (s3.empty() ? "Yes" : "No") << std::endl;

return 0;
}
Static Keyword for Functions – effects The static keyword can be applied to functions in two contexts,
with different effects:
1. Static Member Functions (within a class):
o Effect: As discussed in "Static Data Members/Functions" above, a static member function
belongs to the class itself, not to any particular object. It can be called using the class name
(ClassName::staticFunction()) without creating an object. It can only access static data
members and call other static member functions. It does not have a this pointer.
o Purpose: Utility functions related to the class but not requiring object state, or functions
that operate on static data.
2. Static Global Functions (in C-style programming, or internal linkage in C++ files):
o Effect: When static is applied to a free function (not a member of a class) at the global
scope or file scope, it gives that function internal linkage. This means the function's name
is visible only within the translation unit (the .cpp file) where it is defined. It cannot be
called from other .cpp files.
o Purpose: To create helper functions that are intended for internal use within a specific
source file, preventing naming conflicts with functions in other files and improving
encapsulation at the file level. This is less common in modern C++ where namespaces and
anonymous namespaces are often preferred for this purpose.
Example (Static Global Function):
C++
// file1.cpp
static void helperFunction() { // Internal linkage
std::cout << "Helper function from file1." << std::endl;
}

void somePublicFunction() {
helperFunction(); // Can call it within file1.cpp
}

// file2.cpp
// void anotherFunction() {
// helperFunction(); // ERROR: helperFunction not visible here
// }

23

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy