Study Notes: Object Oriented Concepts with Question Bank and Practicals (Open Elective I)

B. Tech. Third Semester (Information Technology), Rashtrasant Tukadoji Maharaj University, Nagpur

Subject Code: BOE3T01/3

  • Course Objectives
    • Learning to program in an object-oriented programming language, focusing those who already have some experience with another programming language, and who now wish to move on to an object-oriented one.
  • Course Outcomes
    After completion of syllabus, students would be able to:
    • CO 1: Develop programs efficiently using basic features of C++.
    • CO 2: Employ object oriented concepts using classes and objects.
    • CO 3: Explain advanced features of C++ specifically Polymorphism and Inheritance.
    • CO 4: Design programs with dynamic binding to handle the memory efficiently.
    • CO 5: Apply standard templates available in C++.

Syllabus

UNIT 1:
Introduction to Objects, Encapsulation, Polymorphism, Inheritance, Dynamic binding, Message Passing, Abstract Classes, Access Modifiers. Basics of a Typical C++
Environment, Pre-processor Directives, Header Files and Namespaces, Library files.

UNIT 2:
Classes and Data Abstraction: Introduction, Structures – Class -Constructors – Destructors, Const Object And Const Member Functions – Friend Function and Friend Classes, Using This Pointer, Dynamic Memory Allocation, Static Class Members, Container Classes And Integrators, Proxy Classes.

UNIT 3:
Polymorphism and Inheritance: Polymorphism – Function Overloading, Operator Overloading, Inheritance and its types, Casting – Overriding.

UNIT 4:
Virtual Functions and Files handling: Introduction to Virtual Functions – Abstract Base Classes and Concrete Classes – virtual base class – dynamic binding – pure virtual functions. Streams and formatted I/O- File handling – object serialization, namespaces – String – STL.

UNIT 5:
Templates and Exception Handling: Function Templates, Overloading Template Functions, Class Template. Exception Handling: Try, Throw, Catch, Rethrow – Exception specifications.

Unit 1: Introduction to Object-Oriented Concepts and C++ Environment

Unit 1 introduces the core concepts of OOP in C++, including objects, encapsulation, polymorphism, inheritance, dynamic binding, message passing, abstract classes, and access modifiers, which enable modular and reusable code for applications like college management systems in Nagpur. The C++ environment components (preprocessor directives, header files, namespaces, library files) provide the foundation for writing and compiling C++ programs.

1. Introduction to Object-Oriented Programming (OOP)

Object-Oriented Programming (OOP) is a programming paradigm that organizes software design around objects rather than functions and procedures (GeeksforGeeks, 2024). OOP focuses on modeling real-world entities as objects with data and behavior, promoting modularity, reusability, and maintainability.

Key OOP Concepts:

  • Objects: Instances of classes that encapsulate data and behavior.
  • Encapsulation: Bundling data and methods, restricting access to protect data integrity.
  • Polymorphism: Allowing objects to be treated as instances of their parent class, with different behaviors.
  • Inheritance: Enabling a class to inherit properties and methods from another class.
  • Dynamic Binding: Resolving method calls at runtime based on the object’s type.
  • Message Passing: Objects communicating by invoking each other’s methods.
  • Abstract Classes: Classes that cannot be instantiated and serve as blueprints.
  • Access Modifiers: Controlling visibility of class members (public, private, protected).

Example: In a Nagpur college management system, a Student object encapsulates data (e.g., roll number, name) and behavior (e.g., calculate grades), demonstrating OOP principles.

2. Objects

An object is an instance of a class, representing a real-world entity with attributes (data) and methods (functions). Objects are created from classes, which act as templates.

C++ Code: Defining and Using Objects

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

class Student {
public:
    string name;
    int rollNo;
    void display() {
        cout << "Name: " << name << ", Roll No: " << rollNo << endl;
    }
};

int main() {
    Student s1; // Object creation
    s1.name = "Amit";
    s1.rollNo = 101;
    s1.display(); // Output: Name: Amit, Roll No: 101
    return 0;
}

Explanation: This code defines a Student class and creates an object s1, demonstrating how objects encapsulate data (name, rollNo) and behavior (display).

Diagram: Object Representation

Class Student
+--------------+
| name: string |
| rollNo: int  |
| display()    |
+--------------+
   |
   v
Object s1: [name="Amit", rollNo=101]

Explanation: This diagram shows the Student class as a template and s1 as an instance with specific values.

3. Encapsulation

Encapsulation bundles data and methods into a single unit (class) and restricts access to data using access modifiers, ensuring data integrity (Programiz, 2024).

C++ Code: Encapsulation

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

class Student {
private:
    string name;
    int marks;
public:
    void setData(string n, int m) {
        name = n;
        if (m >= 0 && m <= 100) marks = m; // Data validation
    }
    void display() {
        cout << "Name: " << name << ", Marks: " << marks << endl;
    }
};

int main() {
    Student s1;
    s1.setData("Priya", 85);
    s1.display(); // Output: Name: Priya, Marks: 85
    // s1.marks = 200; // Error: marks is private
    return 0;
}

Explanation: This code uses private data members (name, marks) and public methods to control access, ensuring marks is valid (0–100).

4. Polymorphism

Polymorphism allows objects to exhibit different behaviors based on their type or context, achieved via function overloading (compile-time) or virtual functions (runtime).

C++ Code: Polymorphism (Function Overloading)

#include <iostream>
using namespace std;

class Calculator {
public:
    int add(int a, int b) {
        return a + b;
    }
    double add(double a, double b) {
        return a + b;
    }
};

int main() {
    Calculator calc;
    cout << "Int Add: " << calc.add(5, 3) << endl; // Output: 8
    cout << "Double Add: " << calc.add(5.5, 3.2) << endl; // Output: 8.7
    return 0;
}

Explanation: This code demonstrates compile-time polymorphism by overloading the add function for different data types.

5. Inheritance

Inheritance allows a class (derived) to inherit properties and methods from another class (base), promoting code reuse.

C++ Code: Inheritance

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

class Person {
protected:
    string name;
public:
    void setName(string n) { name = n; }
    void display() { cout << "Name: " << name << endl; }
};

class Student : public Person {
public:
    int rollNo;
    void setRollNo(int r) { rollNo = r; }
    void display() {
        cout << "Name: " << name << ", Roll No: " << rollNo << endl;
    }
};

int main() {
    Student s1;
    s1.setName("Rahul");
    s1.setRollNo(102);
    s1.display(); // Output: Name: Rahul, Roll No: 102
    return 0;
}

Explanation: The Student class inherits from Person, reusing name and overriding display to include rollNo.

Diagram: Inheritance

Person
+--------------+
| name: string |
| setName()    |
| display()    |
+--------------+
      ^
      |
Student
+--------------+
| rollNo: int  |
| setRollNo()  |
| display()    |
+--------------+

Explanation: This diagram shows Student inheriting from Person, extending its functionality.

6. Dynamic Binding

Dynamic binding (or late binding) resolves method calls at runtime using virtual functions, enabling polymorphism for derived classes.

C++ Code: Dynamic Binding

#include <iostream>
using namespace std;

class Shape {
public:
    virtual void draw() { // Virtual function
        cout << "Drawing a shape" << endl;
    }
};

class Circle : public Shape {
public:
    void draw() override {
        cout << "Drawing a circle" << endl;
    }
};

int main() {
    Shape* shapePtr = new Circle();
    shapePtr->draw(); // Output: Drawing a circle
    delete shapePtr;
    return 0;
}

Explanation: This code uses a virtual function to achieve runtime polymorphism, calling Circle’s draw method via a Shape pointer.

7. Message Passing

Message passing involves objects communicating by invoking each other’s methods, passing data as parameters.

C++ Code: Message Passing

#include <iostream>
using namespace std;

class Library {
public:
    void issueBook(int bookId) {
        cout << "Book ID " << bookId << " issued" << endl;
    }
};

class Student {
public:
    void requestBook(Library& lib, int bookId) {
        lib.issueBook(bookId); // Message passing
    }
};

int main() {
    Library lib;
    Student s1;
    s1.requestBook(lib, 501); // Output: Book ID 501 issued
    return 0;
}

Explanation: The Student object sends a message to the Library object by calling issueBook, demonstrating object interaction.

8. Abstract Classes

An abstract class contains at least one pure virtual function and cannot be instantiated. It serves as a blueprint for derived classes.

C++ Code: Abstract Class

#include <iostream>
using namespace std;

class Vehicle {
public:
    virtual void start() = 0; // Pure virtual function
};

class Car : public Vehicle {
public:
    void start() override {
        cout << "Car started" << endl;
    }
};

int main() {
    // Vehicle v; // Error: Cannot instantiate abstract class
    Car c;
    c.start(); // Output: Car started
    return 0;
}

Explanation: The Vehicle class is abstract with a pure virtual function start, implemented by the Car class.

9. Access Modifiers

Access modifiers control the visibility of class members:

  • Public: Accessible everywhere.
  • Private: Accessible only within the class.
  • Protected: Accessible in the class and derived classes.

C++ Code: Access Modifiers

#include <iostream>
using namespace std;

class Employee {
private:
    int salary;
protected:
    string dept;
public:
    void setData(int s, string d) {
        salary = s;
        dept = d;
    }
    void display() {
        cout << "Department: " << dept << ", Salary: " << salary << endl;
    }
};

class Manager : public Employee {
public:
    void showDept() {
        cout << "Manager's Department: " << dept << endl; // Accessing protected member
        // cout << salary; // Error: salary is private
    }
};

int main() {
    Manager m;
    m.setData(50000, "IT");
    m.display(); // Output: Department: IT, Salary: 50000
    m.showDept(); // Output: Manager's Department: IT
    return 0;
}

Explanation: This code demonstrates private (salary), protected (dept), and public (setData, display) access modifiers.

10. Basics of a Typical C++ Environment

A C++ program is compiled and executed in an environment that includes:

  • Preprocessor Directives: Commands processed before compilation (e.g., #include, #define).
  • Header Files: Files containing declarations (e.g., iostream, string).
  • Namespaces: Logical groupings to avoid name conflicts (e.g., std).
  • Library Files: Precompiled code linked during compilation (e.g., standard C++ library).

C++ Code: C++ Environment Components

#include <iostream> // Preprocessor directive for header file
#define MAX_SALARY 100000 // Preprocessor directive
using namespace std; // Namespace

class Employee {
public:
    int salary;
    void checkSalary() {
        if (salary > MAX_SALARY)
            cout << "Salary exceeds limit" << endl;
        else
            cout << "Salary: " << salary << endl;
    }
};

int main() {
    Employee e;
    e.salary = 75000;
    e.checkSalary(); // Output: Salary: 75000
    return 0;
}

Explanation: This code uses #include for iostream, #define for a constant, and using namespace std to access standard library functions.

Diagram: C++ Program Structure

Source File (.cpp)
  |
  v
[Preprocessor Directives] --> #include <iostream>, #define MAX_SALARY
  |
  v
[Header Files] --> iostream, string
  |
  v
[Namespaces] --> std
  |
  v
[Main Program] --> Classes, Objects, Methods
  |
  v
[Library Files] --> Linked during compilation
  |
  v
Executable

Explanation: This diagram illustrates the flow from source code to executable, highlighting preprocessor, header files, namespaces, and libraries.

Unit 2: Classes and Data Abstraction in C++

Unit 2 builds on Unit 1 by exploring advanced class features in C++, including constructors, destructors, const objects, friend functions/classes, the this pointer, dynamic memory allocation, static members, container classes, iterators, and proxy classes.

1. Introduction to Classes and Data Abstraction

Classes in C++ are user-defined data types that encapsulate data and methods, implementing the OOP principle of data abstraction. Data abstraction hides implementation details, exposing only essential features to the user (GeeksforGeeks, 2024). Classes enable modularity and abstraction, crucial for building scalable systems like a Nagpur college management system.

Example: A Course class abstracts course details (e.g., code, credits) and operations (e.g., enroll), hiding internal data handling.

2. Structures

A structure in C++ is a user-defined type that groups related data, similar to a class but with default public access. Structures are simpler and often used for plain data aggregation without complex methods.

C++ Code: Structure

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

struct Book {
    string title;
    int id;
    void display() {
        cout << "Book ID: " << id << ", Title: " << title << endl;
    }
};

int main() {
    Book b1 = {"C++ Programming", 101};
    b1.display(); // Output: Book ID: 101, Title: C++ Programming
    return 0;
}

Explanation: This code defines a Book structure with data (title, id) and a method (display), demonstrating a simple data grouping.

Diagram: Structure

Book Structure
+--------------+
| title: string|
| id: int      |
| display()    |
+--------------+
Object b1: [title="C++ Programming", id=101]

Explanation: The diagram shows the Book structure and its instance b1 with specific values.

3. Classes

A class extends the structure concept by supporting encapsulation, access control (public, private, protected), and methods. Classes are the backbone of OOP in C++.

C++ Code: Class

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

class Student {
private:
    string name;
    int rollNo;
public:
    void setData(string n, int r) {
        name = n;
        rollNo = r;
    }
    void display() {
        cout << "Name: " << name << ", Roll No: " << rollNo << endl;
    }
};

int main() {
    Student s1;
    s1.setData("Anjali", 102);
    s1.display(); // Output: Name: Anjali, Roll No: 102
    return 0;
}

Explanation: This code defines a Student class with private data (name, rollNo) and public methods, enforcing encapsulation.

4. Constructors

A constructor is a special member function with the same name as the class, automatically called when an object is created. It initializes object data and has no return type (Programiz, 2024).

Types:

  • Default Constructor: No parameters.
  • Parameterized Constructor: Takes parameters for initialization.
  • Copy Constructor: Initializes an object using another object of the same class.

C++ Code: Constructors

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

class Student {
private:
    string name;
    int rollNo;
public:
    Student() { // Default constructor
        name = "Unknown";
        rollNo = 0;
    }
    Student(string n, int r) { // Parameterized constructor
        name = n;
        rollNo = r;
    }
    Student(const Student& s) { // Copy constructor
        name = s.name;
        rollNo = s.rollNo;
    }
    void display() {
        cout << "Name: " << name << ", Roll No: " << rollNo << endl;
    }
};

int main() {
    Student s1; // Default constructor
    s1.display(); // Output: Name: Unknown, Roll No: 0
    Student s2("Ravi", 103); // Parameterized constructor
    s2.display(); // Output: Name: Ravi, Roll No: 103
    Student s3 = s2; // Copy constructor
    s3.display(); // Output: Name: Ravi, Roll No: 103
    return 0;
}

Explanation: This code demonstrates default, parameterized, and copy constructors for initializing Student objects.

5. Destructors

A destructor is a special member function called when an object goes out of scope or is deleted, used to release resources (e.g., dynamically allocated memory). It has the same name as the class, prefixed with ~, and takes no parameters.

C++ Code: Destructor

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

class Resource {
private:
    string* data;
public:
    Resource(string d) {
        data = new string(d);
        cout << "Resource allocated: " << *data << endl;
    }
    ~Resource() {
        cout << "Resource deallocated: " << *data << endl;
        delete data;
    }
};

int main() {
    Resource r("Database");
    // Output: Resource allocated: Database
    // When r goes out of scope: Resource deallocated: Database
    return 0;
}

Explanation: This code shows a destructor deallocating a dynamically allocated string when the Resource object is destroyed.

6. Const Objects and Const Member Functions

A const object cannot modify its data members, and const member functions guarantee they won’t alter the object’s state. The const keyword is used after the function declaration.

C++ Code: Const Object and Member Function

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

class Student {
private:
    string name;
    int rollNo;
public:
    Student(string n, int r) : name(n), rollNo(r) {}
    void display() const { // Const member function
        cout << "Name: " << name << ", Roll No: " << rollNo << endl;
        // name = "New"; // Error: Cannot modify in const function
    }
};

int main() {
    const Student s("Suman", 104); // Const object
    s.display(); // Output: Name: Suman, Roll No: 104
    // s.setData("New", 105); // Error: Const object cannot call non-const methods
    return 0;
}

Explanation: This code uses a const member function display to safely access data of a const Student object without modification.

7. Friend Functions and Friend Classes

A friend function is a non-member function granted access to a class’s private and protected members. A friend class is a class whose all member functions can access another class’s private members.

C++ Code: Friend Function and Friend Class

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

class Student;

class Library {
public:
    void issueBook(Student& s); // Declaration
};

class Student {
private:
    string name;
    int rollNo;
public:
    Student(string n, int r) : name(n), rollNo(r) {}
    friend void displayStudent(Student& s); // Friend function
    friend class Library; // Friend class
};

void displayStudent(Student& s) {
    cout << "Name: " << s.name << ", Roll No: " << s.rollNo << endl;
}

void Library::issueBook(Student& s) {
    cout << "Book issued to: " << s.name << endl;
}

int main() {
    Student s("Neha", 105);
    displayStudent(s); // Output: Name: Neha, Roll No: 105
    Library lib;
    lib.issueBook(s); // Output: Book issued to: Neha
    return 0;
}

Explanation: The displayStudent friend function and Library friend class access Student’s private members, demonstrating controlled access.

8. Using This Pointer

The this pointer is an implicit pointer in every non-static member function, pointing to the current object. It is used to resolve ambiguity or return the object itself.

C++ Code: This Pointer

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

class Student {
private:
    string name;
    int rollNo;
public:
    Student& setData(string name, int rollNo) {
        this->name = name; // Using this to resolve ambiguity
        this->rollNo = rollNo;
        return *this; // Return current object
    }
    void display() {
        cout << "Name: " << name << ", Roll No: " << rollNo << endl;
    }
};

int main() {
    Student s;
    s.setData("Vikram", 106).display(); // Chaining using this
    // Output: Name: Vikram, Roll No: 106
    return 0;
}

Explanation: The this pointer is used to differentiate member variables from parameters and enable method chaining.

9. Dynamic Memory Allocation

Dynamic memory allocation in C++ uses new and delete operators to allocate and deallocate memory at runtime, allowing flexible memory management.

C++ Code: Dynamic Memory Allocation

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

class Course {
private:
    string* courseName;
public:
    Course(string name) {
        courseName = new string(name);
        cout << "Allocated: " << *courseName << endl;
    }
    ~Course() {
        cout << "Deallocated: " << *courseName << endl;
        delete courseName;
    }
};

int main() {
    Course* c = new Course("Data Structures");
    delete c; // Calls destructor
    // Output: Allocated: Data Structures
    //         Deallocated: Data Structures
    return 0;
}

Explanation: This code allocates memory for courseName dynamically and deallocates it in the destructor, preventing memory leaks.

10. Static Class Members

Static class members are shared across all objects of a class. Static variables maintain a single copy, and static member functions can only access static data.

C++ Code: Static Class Members

#include <iostream>
using namespace std;

class College {
public:
    static int totalStudents; // Static data member
    College() { totalStudents++; }
    static void showTotal() { // Static member function
        cout << "Total Students: " << totalStudents << endl;
    }
};

int College::totalStudents = 0; // Initialize static member

int main() {
    College c1, c2, c3;
    College::showTotal(); // Output: Total Students: 3
    return 0;
}

Explanation: The static totalStudents variable tracks the number of College objects, and the static showTotal function accesses it.

11. Container Classes and Iterators

Container classes store and manage collections of objects (e.g., vector, list in the C++ STL). Iterators are objects that traverse container elements, acting like pointers.

C++ Code: Container Class and Iterator

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

int main() {
    vector<int> marks = {85, 90, 78, 92}; // Container class
    cout << "Student Marks: ";
    for (vector<int>::iterator it = marks.begin(); it != marks.end(); ++it) {
        cout << *it << " "; // Using iterator
    }
    // Output: Student Marks: 85 90 78 92
    cout << endl;
    return 0;
}

Explanation: This code uses the STL vector as a container to store student marks and an iterator to traverse and display them.

Diagram: Container and Iterator

vector<int> marks: [85, 90, 78, 92]
                     ^ Iterator (it)

Explanation: The diagram shows a vector container with an iterator pointing to elements for traversal.

12. Proxy Classes

A proxy class acts as an intermediary to control access to another object, often for resource management, lazy initialization, or security.

C++ Code: Proxy Class

#include <iostream>
using namespace std;

class Database {
private:
    void accessData() {
        cout << "Accessing sensitive database" << endl;
    }
    friend class DatabaseProxy;
};

class DatabaseProxy {
private:
    Database* db;
    bool isAuthorized;
public:
    DatabaseProxy(bool auth) : db(new Database()), isAuthorized(auth) {}
    void access() {
        if (isAuthorized)
            db->accessData();
        else
            cout << "Access denied" << endl;
    }
    ~DatabaseProxy() { delete db; }
};

int main() {
    DatabaseProxy proxy1(true);
    DatabaseProxy proxy2(false);
    proxy1.access(); // Output: Accessing sensitive database
    proxy2.access(); // Output: Access denied
    return 0;
}

Explanation: The DatabaseProxy class controls access to the Database class, allowing access only if authorized, demonstrating controlled resource access.

Unit 3: Polymorphism and Inheritance in C++

Unit 3 deepens the understanding of OOP in C++ by exploring polymorphism (function and operator overloading) and inheritance (single, multiple, multilevel, hierarchical, hybrid). Casting (upcasting and downcasting) and method overriding enable flexible and dynamic behavior in inheritance hierarchies.

1. Polymorphism

Polymorphism allows objects to be treated as instances of their parent class while exhibiting different behaviors, enabling flexibility and reusability (GeeksforGeeks, 2024). It is achieved in C++ through:

  • Compile-time Polymorphism: Function overloading and operator overloading.
  • Runtime Polymorphism: Virtual functions and method overriding (covered later).

Example: In a Nagpur college system, a calculateFee function could behave differently for regular and scholarship students, showcasing polymorphism.

2. Function Overloading

Function overloading allows multiple functions with the same name but different parameter lists (number, type, or order) to coexist in the same scope. The compiler selects the appropriate function based on the arguments provided.

C++ Code: Function Overloading

#include <iostream>
using namespace std;

class Calculator {
public:
    int add(int a, int b) {
        return a + b;
    }
    double add(double a, double b) {
        return a + b;
    }
    int add(int a, int b, int c) {
        return a + b + c;
    }
};

int main() {
    Calculator calc;
    cout << "Add two integers: " << calc.add(5, 3) << endl; // Output: 8
    cout << "Add two doubles: " << calc.add(2.5, 3.7) << endl; // Output: 6.2
    cout << "Add three integers: " << calc.add(1, 2, 3) << endl; // Output: 6
    return 0;
}

Explanation: This code demonstrates function overloading by defining three add functions with different parameter lists, resolved at compile time.

Diagram: Function Overloading

Calculator Class
+--------------+
| add(int, int)|
| add(double, double)|
| add(int, int, int)|
+--------------+
   |
   v
Calls: calc.add(5, 3) -> int version
       calc.add(2.5, 3.7) -> double version

Explanation: The diagram illustrates how the compiler selects the appropriate add function based on argument types.

3. Operator Overloading

Operator overloading allows redefining the behavior of C++ operators (e.g., +, <<) for user-defined types, making them intuitive for objects (Programiz, 2024).

C++ Code: Operator Overloading

#include <iostream>
using namespace std;

class Complex {
private:
    double real, imag;
public:
    Complex(double r = 0, double i = 0) : real(r), imag(i) {}
    Complex operator+(const Complex& other) { // Overload +
        return Complex(real + other.real, imag + other.imag);
    }
    friend ostream& operator<<(ostream& out, const Complex& c) { // Overload <<
        out << c.real << " + " << c.imag << "i";
        return out;
    }
};

int main() {
    Complex c1(3.5, 2.5), c2(1.5, 4.5);
    Complex c3 = c1 + c2; // Uses overloaded +
    cout << "Sum: " << c3 << endl; // Uses overloaded <<, Output: Sum: 5 + 7i
    return 0;
}

Explanation: This code overloads the + operator to add two Complex objects and the << operator to display them, enhancing usability.

Diagram: Operator Overloading

Complex Class
+--------------+
| real: double |
| imag: double |
| operator+()  |
| operator<<() |
+--------------+
   |
   v
c3 = c1 + c2 -> [real=5, imag=7]
cout << c3 -> 5 + 7i

Explanation: The diagram shows how the overloaded + and << operators work with Complex objects.

4. Inheritance and Its Types

Inheritance allows a derived class to inherit properties and methods from a base class, promoting code reuse and hierarchy. C++ supports multiple types of inheritance (GeeksforGeeks, 2024).

Types of Inheritance:

  • Single Inheritance: One base class, one derived class.
  • Multiple Inheritance: One derived class inherits from multiple base classes.
  • Multilevel Inheritance: A derived class becomes a base class for another class.
  • Hierarchical Inheritance: Multiple derived classes inherit from one base class.
  • Hybrid Inheritance: Combination of multiple inheritance types (may require virtual to avoid ambiguity).

C++ Code: Single and Multilevel Inheritance

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

class Person { // Base class
protected:
    string name;
public:
    void setName(string n) { name = n; }
};

class Student : public Person { // Single inheritance
protected:
    int rollNo;
public:
    void setRollNo(int r) { rollNo = r; }
    void display() { cout << "Name: " << name << ", Roll No: " << rollNo << endl; }
};

class Scholar : public Student { // Multilevel inheritance
private:
    double scholarship;
public:
    void setScholarship(double s) { scholarship = s; }
    void display() {
        cout << "Name: " << name << ", Roll No: " << rollNo << ", Scholarship: " << scholarship << endl;
    }
};

int main() {
    Scholar s;
    s.setName("Kiran");
    s.setRollNo(107);
    s.setScholarship(5000.0);
    s.display(); // Output: Name: Kiran, Roll No: 107, Scholarship: 5000
    return 0;
}

Explanation: This code demonstrates single inheritance (Student inherits from Person) and multilevel inheritance (Scholar inherits from Student).

Diagram: Inheritance Types

Person
+--------------+
| name: string |
| setName()    |
+--------------+
      ^
      |
Student
+--------------+
| rollNo: int  |
| setRollNo()  |
| display()    |
+--------------+
      ^
      |
Scholar
+--------------+
| scholarship: double |
| setScholarship()   |
| display()          |
+--------------+

Explanation: The diagram shows multilevel inheritance from Person to Student to Scholar.

C++ Code: Multiple Inheritance

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

class Academic {
protected:
    int marks;
public:
    void setMarks(int m) { marks = m; }
};

class Sports {
protected:
    string sport;
public:
    void setSport(string s) { sport = s; }
};

class Student : public Academic, public Sports {
private:
    string name;
public:
    void setName(string n) { name = n; }
    void display() {
        cout << "Name: " << name << ", Marks: " << marks << ", Sport: " << sport << endl;
    }
};

int main() {
    Student s;
    s.setName("Anita");
    s.setMarks(85);
    s.setSport("Cricket");
    s.display(); // Output: Name: Anita, Marks: 85, Sport: Cricket
    return 0;
}

Explanation: This code shows multiple inheritance, where Student inherits from both Academic and Sports.

5. Casting

Casting converts an object or variable from one type to another. In OOP, casting is used to navigate inheritance hierarchies:

  • Upcasting: Converting a derived class pointer/reference to a base class (implicit, safe).
  • Downcasting: Converting a base class pointer/reference to a derived class (explicit, requires care, often using dynamic_cast).

C++ Code: Casting

#include <iostream>
using namespace std;

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

class Car : public Vehicle {
public:
    void show() override { cout << "Car" << endl; }
    void carDetails() { cout << "Car-specific details" << endl; }
};

int main() {
    Car c;
    Vehicle* v = &c; // Upcasting (implicit)
    v->show(); // Output: Car (due to virtual function)
    
    Vehicle* v2 = new Car();
    Car* c2 = dynamic_cast<Car*>(v2); // Downcasting
    if (c2) c2->carDetails(); // Output: Car-specific details
    delete v2;
    return 0;
}

Explanation: This code demonstrates upcasting (base pointer to derived object) and downcasting (using dynamic_cast for safe conversion).

Diagram: Casting

Car Object
+--------------+
| show()       |
| carDetails() |
+--------------+
   ^ Upcasting
   |
Vehicle* v
   |
   v Downcasting (dynamic_cast)
Car* c2

Explanation: The diagram shows upcasting and downcasting between Vehicle and Car.

6. Overriding

Method overriding occurs when a derived class provides a specific implementation for a virtual function defined in the base class, enabling runtime polymorphism.

C++ Code: Method Overriding

#include <iostream>
using namespace std;

class Animal {
public:
    virtual void sound() { // Virtual function
        cout << "Some animal sound" << endl;
    }
};

class Dog : public Animal {
public:
    void sound() override { // Override
        cout << "Bark" << endl;
    }
};

int main() {
    Animal* animal = new Dog(); // Upcasting
    animal->sound(); // Output: Bark
    delete animal;
    return 0;
}

Explanation: The Dog class overrides the sound method of Animal, and the virtual function ensures the correct method is called at runtime.

Diagram: Method Overriding

Animal
+--------------+
| sound()      |
+--------------+
      ^
      |
Dog
+--------------+
| sound()      | -> "Bark"
+--------------+

Explanation: The diagram shows how Dog overrides Animal’s sound method, called via a base class pointer.

Unit 4: Virtual Functions and File Handling in C++

Unit 4 advances OOP in C++ by exploring virtual functions, abstract and concrete classes, virtual base classes, dynamic binding, and pure virtual functions, enabling flexible and reusable code for systems

1. Introduction to Virtual Functions

Virtual functions in C++ enable runtime polymorphism by allowing derived classes to override base class methods. Declared with the virtual keyword, they ensure the correct method is called based on the object’s actual type, not the pointer or reference type (GeeksforGeeks, 2024).

Key Points:

  • Virtual functions are resolved at runtime via dynamic binding.
  • They are typically used in inheritance hierarchies to customize behavior.

C++ Code: Virtual Function

#include <iostream>
using namespace std;

class Vehicle {
public:
    virtual void start() { // Virtual function
        cout << "Vehicle starting" << endl;
    }
};

class Car : public Vehicle {
public:
    void start() override {
        cout << "Car starting with key" << endl;
    }
};

int main() {
    Vehicle* v = new Car(); // Base class pointer to derived object
    v->start(); // Output: Car starting with key
    delete v;
    return 0;
}

Explanation: The virtual keyword ensures the Car class’s start method is called at runtime, demonstrating runtime polymorphism.

2. Abstract Base Classes and Concrete Classes

An abstract base class cannot be instantiated and contains at least one pure virtual function. A concrete class is a derived class that implements all pure virtual functions, allowing instantiation.

C++ Code: Abstract Base Class and Concrete Class

#include <iostream>
using namespace std;

class Shape { // Abstract base class
public:
    virtual void draw() = 0; // Pure virtual function
    virtual ~Shape() {} // Virtual destructor
};

class Circle : public Shape { // Concrete class
public:
    void draw() override {
        cout << "Drawing a circle" << endl;
    }
};

int main() {
    // Shape s; // Error: Cannot instantiate abstract class
    Shape* s = new Circle();
    s->draw(); // Output: Drawing a circle
    delete s;
    return 0;
}

Explanation: Shape is an abstract base class with a pure virtual function draw, implemented by the concrete Circle class.

Diagram: Abstract and Concrete Classes

Shape (Abstract)
+--------------+
| draw() = 0   |
+--------------+
      ^
      |
Circle (Concrete)
+--------------+
| draw()       |
+--------------+

Explanation: The diagram shows Shape as an abstract base class and Circle as a concrete class implementing draw.

3. Virtual Base Class

A virtual base class is used in multiple inheritance to prevent duplicate copies of a base class in the derived class, avoiding the diamond problem. The virtual keyword ensures only one instance of the base class is shared.

C++ Code: Virtual Base Class

#include <iostream>
using namespace std;

class Person {
protected:
    string name;
public:
    void setName(string n) { name = n; }
    void display() { cout << "Name: " << name << endl; }
};

class Academic : virtual public Person {}; // Virtual inheritance
class Sports : virtual public Person {};   // Virtual inheritance
class Student : public Academic, public Sports {
public:
    void show() {
        display(); // Single copy of Person::name
    }
};

int main() {
    Student s;
    s.setName("Priya");
    s.show(); // Output: Name: Priya
    return 0;
}

Explanation: Virtual inheritance ensures Student has only one copy of Person’s name, resolving the diamond problem.

Diagram: Virtual Base Class (Diamond Problem)

       Person
      /      \
Academic   Sports
      \      /
      Student

Explanation: Without virtual, Student would have two Person copies; virtual inheritance ensures a single shared copy.

4. Dynamic Binding

Dynamic binding (or late binding) resolves function calls at runtime based on the object’s actual type, achieved using virtual functions. It contrasts with static binding, which is resolved at compile time.

C++ Code: Dynamic Binding

#include <iostream>
using namespace std;

class Animal {
public:
    virtual void sound() {
        cout << "Animal sound" << endl;
    }
};

class Dog : public Animal {
public:
    void sound() override {
        cout << "Bark" << endl;
    }
};

int main() {
    Animal* a = new Dog();
    a->sound(); // Output: Bark (resolved at runtime)
    delete a;
    return 0;
}

Explanation: The virtual function sound ensures the Dog class’s implementation is called, demonstrating dynamic binding.

5. Pure Virtual Functions

A pure virtual function is a virtual function declared with = 0, making the class abstract. It must be implemented by derived classes.

C++ Code: Pure Virtual Function

#include <iostream>
using namespace std;

class Device {
public:
    virtual void operate() = 0; // Pure virtual function
};

class Printer : public Device {
public:
    void operate() override {
        cout << "Printing document" << endl;
    }
};

int main() {
    Device* d = new Printer();
    d->operate(); // Output: Printing document
    delete d;
    return 0;
}

Explanation: The Device class is abstract due to the pure virtual function operate, implemented by the Printer class.

6. Streams and Formatted I/O

Streams in C++ handle input/output operations via objects like cin, cout (standard I/O), and fstream (file I/O). Formatted I/O uses manipulators (e.g., setw, setprecision) to control output format (Programiz, 2024).

C++ Code: Formatted I/O

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

int main() {
    double grade = 85.6789;
    cout << fixed << setprecision(2); // Format to 2 decimal places
    cout << "Grade: " << setw(8) << grade << endl; // Output: Grade:    85.68
    int rollNo;
    cout << "Enter Roll No: ";
    cin >> rollNo; // Input stream
    cout << "Roll No: " << rollNo << endl;
    return 0;
}

Explanation: This code uses fixed, setprecision, and setw for formatted output and cin for input, suitable for a student report system.

7. File Handling

File handling in C++ uses the <fstream> library to read from and write to files via ifstream (input), ofstream (output), and fstream (both).

C++ Code: File Handling

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

int main() {
    // Writing to a file
    ofstream outFile("students.txt");
    if (outFile.is_open()) {
        outFile << "Name: Amit, Roll No: 101" << endl;
        outFile.close();
    }
    // Reading from a file
    ifstream inFile("students.txt");
    string line;
    if (inFile.is_open()) {
        while (getline(inFile, line)) {
            cout << line << endl; // Output: Name: Amit, Roll No: 101
        }
        inFile.close();
    }
    return 0;
}

Explanation: This code writes student data to a file and reads it back, demonstrating file I/O for a Nagpur college database.

8. Object Serialization

Object serialization converts an object’s state into a format (e.g., text, binary) for storage or transmission, often used with file handling to persist objects.

C++ Code: Object Serialization

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

class Student {
private:
    string name;
    int rollNo;
public:
    Student(string n = "", int r = 0) : name(n), rollNo(r) {}
    void save(ofstream& out) {
        out << name << "," << rollNo << endl;
    }
    void load(ifstream& in) {
        getline(in, name, ',');
        in >> rollNo;
        in.ignore(); // Clear newline
    }
    void display() {
        cout << "Name: " << name << ", Roll No: " << rollNo << endl;
    }
};

int main() {
    Student s1("Ravi", 108);
    ofstream out("student_data.txt");
    s1.save(out); // Serialize
    out.close();
    
    Student s2;
    ifstream in("student_data.txt");
    s2.load(in); // Deserialize
    in.close();
    s2.display(); // Output: Name: Ravi, Roll No: 108
    return 0;
}

Explanation: This code serializes a Student object to a file and deserializes it, preserving object state for persistent storage.

9. Namespaces

Namespaces group related identifiers (classes, functions, variables) to avoid name conflicts. The using directive or scope resolution operator (::) accesses namespace members.

C++ Code: Namespaces

#include <iostream>
using namespace std;

namespace College {
    class Department {
    public:
        void show() {
            cout << "IT Department, Nagpur" << endl;
        }
    };
}

namespace University {
    class Department {
    public:
        void show() {
            cout << "University Department" << endl;
        }
    };
}

int main() {
    College::Department d1;
    University::Department d2;
    d1.show(); // Output: IT Department, Nagpur
    d2.show(); // Output: University Department
    return 0;
}

Explanation: This code uses namespaces to distinguish between Department classes, preventing name conflicts.

Diagram: Namespaces

College Namespace       University Namespace
+--------------+       +--------------+
| Department   |       | Department   |
|   show()     |       |   show()     |
+--------------+       +--------------+

Explanation: The diagram shows two Department classes in separate namespaces, avoiding conflicts.

10. String

The C++ string class (<string> library) provides a convenient way to handle strings, supporting operations like concatenation, comparison, and substring extraction.

C++ Code: String

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

int main() {
    string name = "Nagpur";
    string college = "College";
    string fullName = name + " " + college; // Concatenation
    cout << "Full Name: " << fullName << endl; // Output: Full Name: Nagpur College
    cout << "Length: " << fullName.length() << endl; // Output: Length: 14
    cout << "Substring: " << fullName.substr(0, 6) << endl; // Output: Substring: Nagpur
    return 0;
}

Explanation: This code demonstrates string operations like concatenation and substring, useful for text processing in a college system.

11. Standard Template Library (STL)

The STL provides reusable, generic data structures and algorithms, including containers (vector, list), iterators, and algorithms (sort, find) (GeeksforGeeks, 2024).

C++ Code: STL

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> grades = {85, 92, 78, 95};
    cout << "Original Grades: ";
    for (int g : grades) cout << g << " ";
    cout << endl;
    
    sort(grades.begin(), grades.end()); // STL algorithm
    cout << "Sorted Grades: ";
    for (int g : grades) cout << g << " ";
    cout << endl; // Output: Sorted Grades: 78 85 92 95
    
    auto it = find(grades.begin(), grades.end(), 92); // STL iterator
    if (it != grades.end())
        cout << "Found 92 at position: " << distance(grades.begin(), it) << endl;
    return 0;
}

Explanation: This code uses STL’s vector (container), sort and find (algorithms), and iterators to manage student grades.

Diagram: STL Components

vector<int> grades: [85, 92, 78, 95]
   |                ^
   |                Iterator
   v
sort() -> [78, 85, 92, 95]
find(92) -> Iterator at position 2

Explanation: The diagram shows a vector with STL operations for sorting and searching.

Unit 5: Templates and Exception Handling in C++

Unit 5 completes the exploration of OOP in C++ by introducing templates for generic programming, enabling reusable code for functions and classes, and exception handling for robust error management. Function templates, overloaded template functions, and class templates support flexible data processing, while try, throw, catch, rethrow, and exception specifications ensure reliable error handling in applications

1. Templates

Templates in C++ enable generic programming, allowing functions and classes to work with any data type. Templates promote code reuse by defining generic algorithms or data structures, resolved at compile time (GeeksforGeeks, 2024).

Example: A generic function to calculate the maximum marks of students, applicable to integers or floating-point grades in a Nagpur college system.

1.1 Function Templates

A function template defines a generic function that can operate on any data type, using the template keyword and a placeholder type (e.g., T).

C++ Code: Function Template

#include <iostream>
using namespace std;

template <typename T>
T maximum(T a, T b) {
    return (a > b) ? a : b;
}

int main() {
    cout << "Max of integers: " << maximum(10, 20) << endl; // Output: 20
    cout << "Max of doubles: " << maximum(15.5, 12.3) << endl; // Output: 15.5
    return 0;
}

Explanation: The maximum function template works with any comparable type (int, double), demonstrating generic programming.

Diagram: Function Template

Template: maximum<T>(a, b)
   |
   v
Instantiation:
- maximum<int>(10, 20) -> Returns 20
- maximum<double>(15.5, 12.3) -> Returns 15.5

Explanation: The diagram shows how the maximum template is instantiated for different types at compile time.

1.2 Overloading Template Functions

Overloading template functions allows defining multiple function templates or a combination of template and non-template functions with the same name but different parameter lists. The compiler selects the most specific function.

C++ Code: Overloading Template Functions

#include <iostream>
using namespace std;

template <typename T>
void print(T value) {
    cout << "Generic: " << value << endl;
}

template <typename T1, typename T2>
void print(T1 a, T2 b) {
    cout << "Two types: " << a << ", " << b << endl;
}

void print(int x) { // Non-template function
    cout << "Specific int: " << x << endl;
}

int main() {
    print(42); // Calls non-template function, Output: Specific int: 42
    print(3.14); // Calls single-parameter template, Output: Generic: 3.14
    print(10, "Hello"); // Calls two-parameter template, Output: Two types: 10, Hello
    return 0;
}

Explanation: This code demonstrates overloading with a specific non-template function, a single-parameter template, and a two-parameter template, showcasing function selection priority.

1.3 Class Templates

A class template defines a generic class that can work with any data type, useful for creating reusable data structures like arrays or lists.

C++ Code: Class Template

#include <iostream>
using namespace std;

template <typename T>
class Array {
private:
    T* data;
    int size;
public:
    Array(int s) : size(s) {
        data = new T[size];
    }
    ~Array() {
        delete[] data;
    }
    void set(int index, T value) {
        if (index >= 0 && index < size) data[index] = value;
    }
    void display() {
        for (int i = 0; i < size; i++)
            cout << data[i] << " ";
        cout << endl;
    }
};

int main() {
    Array<int> intArray(3);
    intArray.set(0, 85);
    intArray.set(1, 90);
    intArray.set(2, 95);
    cout << "Integer Array: ";
    intArray.display(); // Output: Integer Array: 85 90 95
    
    Array<double> doubleArray(2);
    doubleArray.set(0, 92.5);
    doubleArray.set(1, 88.7);
    cout << "Double Array: ";
    doubleArray.display(); // Output: Double Array: 92.5 88.7
    return 0;
}

Explanation: The Array class template stores elements of any type (int, double), demonstrating generic data structures for a student marks system.

Diagram: Class Template

Array<T> Class
+--------------+
| data: T*     |
| size: int    |
| set()        |
| display()    |
+--------------+
   |
   v
Instantiations:
- Array<int> -> [85, 90, 95]
- Array<double> -> [92.5, 88.7]

Explanation: The diagram shows the Array template instantiated for int and double types.

2. Exception Handling

Exception handling in C++ manages runtime errors gracefully using try, throw, and catch blocks, ensuring robust programs (Programiz, 2024).

Key Components:

  • Try: Encloses code that may throw an exception.
  • Throw: Signals an exception with a value or object.
  • Catch: Handles the thrown exception.
  • Rethrow: Propagates an exception to an outer catch block.
  • Exception Specifications: Restrict the types of exceptions a function can throw (deprecated in modern C++ but part of the syllabus).

Example: Handling invalid input in a Nagpur college grading system to prevent program crashes.

2.1 Try, Throw, Catch

The try block contains code that might throw an exception, throw raises the exception, and catch handles it.

C++ Code: Try, Throw, Catch

#include <iostream>
using namespace std;

int divide(int a, int b) {
    if (b == 0)
        throw string("Division by zero");
    return a / b;
}

int main() {
    try {
        int result = divide(10, 0);
        cout << "Result: " << result << endl;
    } catch (const string& e) {
        cout << "Error: " << e << endl; // Output: Error: Division by zero
    }
    return 0;
}

Explanation: This code throws a string exception when dividing by zero, caught and handled in the catch block.

Diagram: Exception Handling

try {
    divide(10, 0) -> throw "Division by zero"
}
   |
   v
catch (string& e) -> Prints "Error: Division by zero"

Explanation: The diagram shows the flow from try to throw to catch for handling a division error.

2.2 Rethrow

Rethrow uses throw without arguments in a catch block to propagate the caught exception to an outer try-catch block.

C++ Code: Rethrow

#include <iostream>
using namespace std;

void process(int value) {
    try {
        if (value < 0)
            throw value;
        cout << "Value: " << value << endl;
    } catch (int e) {
        cout << "Inner catch: Negative value " << e << endl;
        throw; // Rethrow
    }
}

int main() {
    try {
        process(-5);
    } catch (int e) {
        cout << "Outer catch: Error value " << e << endl; // Output: Inner catch: Negative value -5
                                                            //         Outer catch: Error value -5
    }
    return 0;
}

Explanation: The exception is caught in process, partially handled, and rethrown to the outer catch block for further handling.

2.3 Exception Specifications

Exception specifications (using throw(type) in older C++ or noexcept in modern C++) indicate which exceptions a function may throw. Note: Exception specifications are deprecated in C++11 and later, but included here as per the syllabus.

C++ Code: Exception Specification

#include <iostream>
using namespace std;

void compute(int x) throw(int) { // Exception specification
    if (x < 0)
        throw x;
    cout << "Computed: " << x * 2 << endl;
}

int main() {
    try {
        compute(-3);
    } catch (int e) {
        cout << "Caught negative value: " << e << endl; // Output: Caught negative value: -3
    }
    compute(5); // Output: Computed: 10
    return 0;
}

Explanation: The throw(int) specification indicates compute can only throw int exceptions, handled in the catch block.

Question Bank: Object Oriented Concepts using C++

Unit 1: Introduction to Objects and C++ Environment

  1. Define object-oriented programming (OOP) and list its four main principles.
    Bloom’s Level: Remembering
  2. Explain the concept of encapsulation with an example from a Nagpur college system.
    Bloom’s Level: Understanding
  3. Write a C++ program to create a Book class with attributes title and id, and a method to display them.
    Bloom’s Level: Applying
  4. Analyze the difference between compile-time and runtime polymorphism with examples.
    Bloom’s Level: Analyzing
  5. What is inheritance? Describe its benefits in software development.
    Bloom’s Level: Understanding
  6. Write a C++ program to demonstrate dynamic binding using virtual functions.
    Bloom’s Level: Applying
  7. Explain the concept of message passing with a real-world example.
    Bloom’s Level: Understanding
  8. Write a C++ program to create an abstract class Shape with a pure virtual function area.
    Bloom’s Level: Applying
  9. Evaluate the role of access modifiers in achieving data hiding in OOP.
    Bloom’s Level: Evaluating
  10. Design a C++ program to model a Student class with private attributes and public methods for a college database.
    Bloom’s Level: Creating
  11. What are preprocessor directives? List three examples used in C++.
    Bloom’s Level: Remembering
  12. Write a C++ program using a header file to define a Library class.
    Bloom’s Level: Applying
  13. Analyze the purpose of namespaces in preventing name conflicts in C++.
    Bloom’s Level: Analyzing
  14. Create a flowchart to illustrate the execution of a C++ program with preprocessor directives.
    Bloom’s Level: Creating
  15. Explain the role of library files in a C++ environment with examples.
    Bloom’s Level: Understanding
  16. Write a C++ program to demonstrate the use of the std namespace for I/O operations.
    Bloom’s Level: Applying
  17. Compare public, private, and protected access modifiers with their impact on inheritance.
    Bloom’s Level: Analyzing
  18. Evaluate the suitability of abstract classes for modeling a vehicle management system.
    Bloom’s Level: Evaluating
  19. What is dynamic binding? Provide an example where it is essential.
    Bloom’s Level: Remembering
  20. Design a C++ system to model a Nagpur college alumni network using objects and message passing.
    Bloom’s Level: Creating

Unit 2: Classes and Data Abstraction

  1. Define a class in C++ and list its key components.
    Bloom’s Level: Remembering
  2. Explain the difference between a structure and a class in C++ with an example.
    Bloom’s Level: Understanding
  3. Write a C++ program to implement a Course class with a parameterized constructor.
    Bloom’s Level: Applying
  4. Analyze the role of destructors in memory management with an example.
    Bloom’s Level: Analyzing
  5. What is a const member function? Explain its use with a real-world example.
    Bloom’s Level: Understanding
  6. Write a C++ program to demonstrate a friend function accessing private members of a class.
    Bloom’s Level: Applying
  7. Explain the purpose of the this pointer in C++ with an example.
    Bloom’s Level: Understanding
  8. Write a C++ program to implement dynamic memory allocation for a Student class.
    Bloom’s Level: Applying
  9. Evaluate the advantages of using static class members in a college management system.
    Bloom’s Level: Evaluating
  10. Design a C++ program to create a container class for storing student grades using a vector.
    Bloom’s Level: Creating
  11. What is a friend class? Provide an example of its application.
    Bloom’s Level: Remembering
  12. Write a C++ program to implement a copy constructor for a Book class.
    Bloom’s Level: Applying
  13. Analyze the benefits and risks of dynamic memory allocation in C++.
    Bloom’s Level: Analyzing
  14. Create a flowchart for a destructor in a class managing IoT device data.
    Bloom’s Level: Creating
  15. Explain the role of iterators in container classes with an example.
    Bloom’s Level: Understanding
  16. Write a C++ program to implement a proxy class for controlling access to a database.
    Bloom’s Level: Applying
  17. Compare the use of const objects and non-const objects in C++ programs.
    Bloom’s Level: Analyzing
  18. Evaluate the use of friend functions versus public methods for accessing private data.
    Bloom’s Level: Evaluating
  19. What are static class members? Provide two real-world examples.
    Bloom’s Level: Remembering
  20. Design a C++ system to manage a library book inventory using a container class and iterators.
    Bloom’s Level: Creating

Unit 3: Polymorphism and Inheritance

  1. Define polymorphism and list its types in C++.
    Bloom’s Level: Remembering
  2. Explain function overloading with an example from a Nagpur college system.
    Bloom’s Level: Understanding
  3. Write a C++ program to overload the + operator for adding two Complex number objects.
    Bloom’s Level: Applying
  4. Analyze the advantages and limitations of operator overloading in C++.
    Bloom’s Level: Analyzing
  5. What are the different types of inheritance? Provide an example for each.
    Bloom’s Level: Remembering
  6. Write a C++ program to implement multilevel inheritance for a student grading system.
    Bloom’s Level: Applying
  7. Explain the concept of upcasting and downcasting with a real-world example.
    Bloom’s Level: Understanding
  8. Write a C++ program to demonstrate method overriding in a vehicle hierarchy.
    Bloom’s Level: Applying
  9. Evaluate the suitability of multiple inheritance for modeling a student-athlete system.
    Bloom’s Level: Evaluating
  10. Design an algorithm for overloading the * operator to multiply two matrices.
    Bloom’s Level: Creating
  11. What is method overriding? Explain its significance in OOP.
    Bloom’s Level: Remembering
  12. Write a C++ program to implement hierarchical inheritance for a library system.
    Bloom’s Level: Applying
  13. Analyze the challenges of multiple inheritance and how virtual inheritance resolves them.
    Bloom’s Level: Analyzing
  14. Create a flowchart for a program demonstrating function overloading in a calculator class.
    Bloom’s Level: Creating
  15. Explain the role of the virtual keyword in achieving runtime polymorphism.
    Bloom’s Level: Understanding
  16. Write a C++ program to perform downcasting using dynamic_cast in an inheritance hierarchy.
    Bloom’s Level: Applying
  17. Compare single and multiple inheritance in terms of complexity and use cases.
    Bloom’s Level: Analyzing
  18. Evaluate the impact of operator overloading on code readability and maintenance.
    Bloom’s Level: Evaluating
  19. What is the diamond problem in multiple inheritance? Provide a solution.
    Bloom’s Level: Remembering
  20. Design a C++ system to model a Nagpur bus route hierarchy using inheritance and polymorphism.
    Bloom’s Level: Creating

Unit 4: Virtual Functions and File Handling

  1. Define a virtual function and list its key characteristics.
    Bloom’s Level: Remembering
  2. Explain the difference between abstract base classes and concrete classes with an example.
    Bloom’s Level: Understanding
  3. Write a C++ program to implement a pure virtual function in an abstract class Shape.
    Bloom’s Level: Applying
  4. Analyze the role of virtual base classes in resolving the diamond problem.
    Bloom’s Level: Analyzing
  5. What is dynamic binding? Explain its importance in runtime polymorphism.
    Bloom’s Level: Understanding
  6. Write a C++ program to demonstrate dynamic binding using virtual functions in a vehicle system.
    Bloom’s Level: Applying
  7. Explain the use of formatted I/O in C++ with an example of student data display.
    Bloom’s Level: Understanding
  8. Write a C++ program to write student records to a file and read them back.
    Bloom’s Level: Applying
  9. Evaluate the use of object serialization in a college database system.
    Bloom’s Level: Evaluating
  10. Design a C++ program to serialize and deserialize a Course object to a file.
    Bloom’s Level: Creating
  11. What is a namespace? Provide two examples of its use in C++.
    Bloom’s Level: Remembering
  12. Write a C++ program to demonstrate the use of the string class for text processing.
    Bloom’s Level: Applying
  13. Analyze the advantages of using the STL over custom data structures.
    Bloom’s Level: Analyzing
  14. Create a flowchart for reading and writing to a file using C++ streams.
    Bloom’s Level: Creating
  15. Explain the role of iterators in the STL with an example.
    Bloom’s Level: Understanding
  16. Write a C++ program to sort a vector of student grades using STL algorithms.
    Bloom’s Level: Applying
  17. Compare file handling in C++ using streams versus traditional C file operations.
    Bloom’s Level: Analyzing
  18. Evaluate the efficiency of virtual functions in large inheritance hierarchies.
    Bloom’s Level: Evaluating
  19. What is object serialization? Provide an example of its application.
    Bloom’s Level: Remembering
  20. Design a C++ system to manage IoT sensor data using file handling and STL.
    Bloom’s Level: Creating

Unit 5: Templates and Exception Handling

  1. Define a function template and list its benefits in C++.
    Bloom’s Level: Remembering
  2. Explain how function templates support generic programming with an example.
    Bloom’s Level: Understanding
  3. Write a C++ program to implement a function template for finding the minimum of two values.
    Bloom’s Level: Applying
  4. Analyze the advantages of overloading template functions over regular function overloading.
    Bloom’s Level: Analyzing
  5. What is a class template? Provide an example of its use.
    Bloom’s Level: Remembering
  6. Write a C++ program to implement a class template for a stack data structure.
    Bloom’s Level: Applying
  7. Explain the try-catch mechanism in C++ with a real-world example.
    Bloom’s Level: Understanding
  8. Write a C++ program to handle a division-by-zero exception using try-catch.
    Bloom’s Level: Applying
  9. Evaluate the role of exception handling in making C++ programs robust.
    Bloom’s Level: Evaluating
  10. Design an algorithm for a class template to manage a dynamic array of any type.
    Bloom’s Level: Creating
  11. What is rethrowing an exception? Provide an example of its use.
    Bloom’s Level: Remembering
  12. Write a C++ program to demonstrate rethrowing an exception in a nested try-catch block.
    Bloom’s Level: Applying
  13. Analyze the limitations of exception specifications in modern C++.
    Bloom’s Level: Analyzing
  14. Create a flowchart for a program handling multiple exceptions in a grading system.
    Bloom’s Level: Creating
  15. Explain the benefits of class templates in implementing reusable data structures.
    Bloom’s Level: Understanding
  16. Write a C++ program to overload a template function for printing different data types.
    Bloom’s Level: Applying
  17. Compare function templates and class templates in terms of flexibility and use cases.
    Bloom’s Level: Analyzing
  18. Evaluate the trade-offs between using templates and inheritance for code reuse.
    Bloom’s Level: Evaluating
  19. What are exception specifications? Explain their purpose in older C++ code.
    Bloom’s Level: Remembering
  20. Design a C++ system to manage a Nagpur library using class templates and exception handling.
    Bloom’s Level: Creating

List of 12 Practicals for Object Oriented Concepts using C++ Lab

Practical 1: Implementing a Class with Encapsulation

Unit: 1 (Introduction to Objects and C++ Environment)

Objective: Implement a class with encapsulation to manage student data.

Description: Write a C++ program to create a Student class with private attributes (name, rollNo) and public methods (setData, display) to enforce encapsulation. Accept student details as input and display them, ensuring data is only modified through methods.

Expected Outcome: Students will understand encapsulation and access modifiers, applicable to secure data management in a Nagpur college system.

Sample Code Snippet:

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

class Student {
private:
    string name;
    int rollNo;
public:
    void setData(string n, int r) {
        name = n;
        rollNo = r;
    }
    void display() {
        cout << "Name: " << name << ", Roll No: " << rollNo << endl;
    }
};

int main() {
    Student s;
    s.setData("Amit", 101);
    s.display(); // Output: Name: Amit, Roll No: 101
    return 0;
}

Practical 2: Demonstrating Dynamic Binding

Unit: 1 (Introduction to Objects and C++ Environment)

Objective: Implement dynamic binding using virtual functions.

Description: Write a C++ program to create a base class Vehicle with a virtual function start and a derived class Car that overrides it. Use a base class pointer to demonstrate runtime polymorphism.

Expected Outcome: Students will learn dynamic binding and its role in runtime polymorphism, useful for flexible system designs.

Sample Code Snippet:

#include <iostream>
using namespace std;

class Vehicle {
public:
    virtual void start() {
        cout << "Vehicle starting" << endl;
    }
};

class Car : public Vehicle {
public:
    void start() override {
        cout << "Car starting with key" << endl;
    }
};

int main() {
    Vehicle* v = new Car();
    v->start(); // Output: Car starting with key
    delete v;
    return 0;
}

Practical 3: Using Constructors and Destructors

Unit: 2 (Classes and Data Abstraction)

Objective: Implement a class with constructors and destructors for resource management.

Description: Write a C++ program to create a Course class with a default constructor, parameterized constructor, and destructor to manage dynamically allocated memory for courseName. Demonstrate object creation and destruction.

Expected Outcome: Students will understand constructor/destructor usage and memory management, applicable to IoT device control.

Sample Code Snippet:

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

class Course {
private:
    string* courseName;
public:
    Course() : courseName(new string("Unknown")) {
        cout << "Default Constructor: " << *courseName << endl;
    }
    Course(string name) : courseName(new string(name)) {
        cout << "Parameterized Constructor: " << *courseName << endl;
    }
    ~Course() {
        cout << "Destructor: " << *courseName << endl;
        delete courseName;
    }
};

int main() {
    Course c1;
    Course c2("Data Structures");
    return 0; // Destructors called automatically
    // Output: Default Constructor: Unknown
    //         Parameterized Constructor: Data Structures
    //         Destructor: Data Structures
    //         Destructor: Unknown
}

Practical 4: Implementing Friend Function and This Pointer

Unit: 2 (Classes and Data Abstraction)

Objective: Demonstrate friend functions and the this pointer in a class.

Description: Write a C++ program to create a Student class with a friend function to access private data and a method using the this pointer for method chaining. Accept and display student details.

Expected Outcome: Students will learn controlled access via friend functions and method chaining, useful for complex object interactions.

Sample Code Snippet:

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

class Student {
private:
    string name;
    int rollNo;
public:
    Student& setData(string name, int rollNo) {
        this->name = name;
        this->rollNo = rollNo;
        return *this;
    }
    friend void displayStudent(Student& s);
};

void displayStudent(Student& s) {
    cout << "Name: " << s.name << ", Roll No: " << s.rollNo << endl;
}

int main() {
    Student s;
    s.setData("Neha", 102).setData("Ravi", 103); // Chaining
    displayStudent(s); // Output: Name: Ravi, Roll No: 103
    return 0;
}

Practical 5: Using Container Classes and Iterators

Unit: 2 (Classes and Data Abstraction)

Objective: Implement a container class using STL vector and iterators.

Description: Write a C++ program to create a vector to store student grades, use iterators to traverse and display the grades, and perform basic operations like adding and removing elements.

Expected Outcome: Students will understand STL containers and iterators, applicable to data management in college systems.

Sample Code Snippet:

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

int main() {
    vector<int> grades;
    grades.push_back(85);
    grades.push_back(90);
    grades.push_back(78);
    cout << "Grades: ";
    for (vector<int>::iterator it = grades.begin(); it != grades.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl; // Output: Grades: 85 90 78
    return 0;
}

Practical 6: Implementing Function Overloading

Unit: 3 (Polymorphism and Inheritance)

Objective: Implement function overloading in a class.

Description: Write a C++ program to create a Calculator class with overloaded calculate functions to compute the area of a circle (given radius) and a rectangle (given length and width). Accept inputs and display results.

Expected Outcome: Students will learn compile-time polymorphism, applicable to mathematical computations in AI systems.

Sample Code Snippet:

#include <iostream>
using namespace std;

class Calculator {
public:
    double calculate(double radius) {
        return 3.14 * radius * radius;
    }
    double calculate(double length, double width) {
        return length * width;
    }
};

int main() {
    Calculator calc;
    cout << "Circle Area: " << calc.calculate(5.0) << endl; // Output: 78.5
    cout << "Rectangle Area: " << calc.calculate(4.0, 6.0) << endl; // Output: 24
    return 0;
}

Practical 7: Operator Overloading

Unit: 3 (Polymorphism and Inheritance)

Objective: Implement operator overloading for a user-defined type.

Description: Write a C++ program to create a Complex class and overload the + operator to add two complex numbers. Accept complex number inputs and display the sum.

Expected Outcome: Students will understand operator overloading, useful for intuitive data manipulation in scientific applications.

Sample Code Snippet:

#include <iostream>
using namespace std;

class Complex {
private:
    double real, imag;
public:
    Complex(double r = 0, double i = 0) : real(r), imag(i) {}
    Complex operator+(const Complex& other) {
        return Complex(real + other.real, imag + other.imag);
    }
    void display() {
        cout << real << " + " << imag << "i" << endl;
    }
};

int main() {
    Complex c1(3.5, 2.5), c2(1.5, 4.5);
    Complex c3 = c1 + c2;
    cout << "Sum: ";
    c3.display(); // Output: Sum: 5 + 7i
    return 0;
}

Practical 8: Implementing Multiple Inheritance

Unit: 3 (Polymorphism and Inheritance)

Objective: Demonstrate multiple inheritance in a class hierarchy.

Description: Write a C++ program to create a Student class that inherits from Academic (marks) and Sports (sport name) classes. Implement methods to set and display student details.

Expected Outcome: Students will learn multiple inheritance, applicable to modeling multifaceted entities like student-athletes.

Sample Code Snippet:

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

class Academic {
protected:
    int marks;
public:
    void setMarks(int m) { marks = m; }
};

class Sports {
protected:
    string sport;
public:
    void setSport(string s) { sport = s; }
};

class Student : public Academic, public Sports {
private:
    string name;
public:
    void setName(string n) { name = n; }
    void display() {
        cout << "Name: " << name << ", Marks: " << marks << ", Sport: " << sport << endl;
    }
};

int main() {
    Student s;
    s.setName("Anita");
    s.setMarks(85);
    s.setSport("Cricket");
    s.display(); // Output: Name: Anita, Marks: 85, Sport: Cricket
    return 0;
}

Practical 9: Implementing Virtual Functions

Unit: 4 (Virtual Functions and File Handling)

Objective: Implement virtual functions for runtime polymorphism.

Description: Write a C++ program to create an abstract base class Device with a pure virtual function operate. Derive a Printer class to implement operate and demonstrate runtime polymorphism using a base class pointer.

Expected Outcome: Students will understand virtual functions and abstract classes, applicable to IoT device management.

Sample Code Snippet:

#include <iostream>
using namespace std;

class Device {
public:
    virtual void operate() = 0;
    virtual ~Device() {}
};

class Printer : public Device {
public:
    void operate() override {
        cout << "Printing document" << endl;
    }
};

int main() {
    Device* d = new Printer();
    d->operate(); // Output: Printing document
    delete d;
    return 0;
}

Practical 10: File Handling for Student Records

Unit: 4 (Virtual Functions and File Handling)

Objective: Implement file handling to store and retrieve student data.

Description: Write a C++ program to create a Student class and write its objects (name, rollNo) to a file using ofstream. Read and display the records using ifstream.

Expected Outcome: Students will learn file I/O, applicable to persistent storage in college databases.

Sample Code Snippet:

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

class Student {
public:
    string name;
    int rollNo;
    void save(ofstream& out) {
        out << name << "," << rollNo << endl;
    }
    void load(ifstream& in) {
        getline(in, name, ',');
        in >> rollNo;
        in.ignore();
    }
};

int main() {
    Student s1;
    s1.name = "Ravi";
    s1.rollNo = 104;
    ofstream out("students.txt");
    s1.save(out);
    out.close();
    
    Student s2;
    ifstream in("students.txt");
    s2.load(in);
    in.close();
    cout << "Name: " << s2.name << ", Roll No: " << s2.rollNo << endl; // Output: Name: Ravi, Roll No: 104
    return 0;
}

Practical 11: Using STL for Sorting Grades

Unit: 4 (Virtual Functions and File Handling)

Objective: Use STL to manage and sort student grades.

Description: Write a C++ program to store student grades in a vector, use STL sort algorithm to sort them, and display using iterators. Allow users to add grades dynamically.

Expected Outcome: Students will learn STL containers and algorithms, useful for efficient data processing in AI applications.

Sample Code Snippet:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    vector<int> grades;
    grades.push_back(85);
    grades.push_back(92);
    grades.push_back(78);
    sort(grades.begin(), grades.end());
    cout << "Sorted Grades: ";
    for (auto it = grades.begin(); it != grades.end(); ++it) {
        cout << *it << " ";
    }
    cout << endl; // Output: Sorted Grades: 78 85 92
    return 0;
}

Practical 12: Implementing Class Template with Exception Handling

Unit: 5 (Templates and Exception Handling)

Objective: Implement a class template with exception handling for a stack.

Description: Write a C++ program to create a class template Stack for any data type, with push and pop operations. Include exception handling for stack overflow and underflow conditions. Test with integer and string stacks.

Expected Outcome: Students will master generic programming and error handling, applicable to robust data structures in IoT systems.

Sample Code Snippet:

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

template <typename T>
class Stack {
private:
    T* data;
    int top;
    int capacity;
public:
    Stack(int size) : capacity(size), top(-1) {
        data = new T[size];
    }
    ~Stack() {
        delete[] data;
    }
    void push(T value) {
        if (top >= capacity - 1)
            throw string("Stack Overflow");
        data[++top] = value;
    }
    T pop() {
        if (top < 0)
            throw string("Stack Underflow");
        return data[top--];
    }
};

int main() {
    try {
        Stack<int> intStack(2);
        intStack.push(10);
        intStack.push(20);
        cout << "Popped: " << intStack.pop() << endl; // Output: Popped: 20
        
        Stack<string> strStack(2);
        strStack.push("AI");
        cout << "Popped: " << strStack.pop() << endl; // Output: Popped: AI
        strStack.pop(); // Throws exception
    } catch (const string& e) {
        cout << "Error: " << e << endl; // Output: Error: Stack Underflow
    }
    return 0;
}

Author

  • Dr. Anil Warbhe is a freelance technical consultant and a passionate advocate for simplifying complex technologies. His expertise lies in developing custom mobile applications, websites, and web applications, providing technical consultancy on server administration, and offering insightful perspectives on current tech trends through his writing.

    View all posts

Leave a Reply

Your email address will not be published. Required fields are marked *