BCS 31 3 Sesson Combo
BCS 31 3 Sesson Combo
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
// 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;
}
};
// 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
// 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);
};
// 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;
}
};
// 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).
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)
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
}
// In main:
// Point p(10, 20);
// p.display();
// p.setX(15);
// p.display();
// p.moveBy(5, 5).display(); // Chaining calls using 'this' pointer
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;
}
};
// 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;
8
instance = new Singleton();
}
return instance;
}
// Delete copy constructor and assignment operator to prevent copying
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
};
// 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
// 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;
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;
}
};
// 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; }
// 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;
}
};
// 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;
// }
int main() {
std::string textToAppend = "\nThis text is appended.\n";
if (outFile.is_open()) {
outFile << textToAppend;
outFile.close();
std::cout << "Text appended to my_log.txt" << std::endl;
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>
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 << "Contents of 'output queue' (retrieved from stream):" << std::endl;
std::cout << outputStream.str(); // Retrieve full output string
}
16
// Enqueue operations
std::cout << "Enqueuing: Apple, Banana, Cherry" << std::endl;
myQueue.push("Apple");
myQueue.push("Banana");
myQueue.push("Cherry");
// 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.
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
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
int main() {
try {
double result1 = divide(10.0, 2.0);
std::cout << "10 / 2 = " << result1 << std::endl;
🟨 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;
// 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;
}
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