Object-Oriented Programming (OOP)

Unit 5 · 10 teaching hours · 37 min read

Object-Oriented Programming (OOP)

What the syllabus asks for 4
  • Programming paradigms: procedural, structural and object oriented
  • Features of OOP: Class, Object, Polymorphism and Inheritance
  • Advantages of OOP
  • Application of OOP

Every program you wrote in Unit 4 was a list of instructions that pushed data around: main() called a function, the function worked on variables, and the variables sat outside in the open.

Object-oriented programming turns that picture inside out. Data and the code that is allowed to touch it are locked together into one unit called an object, and a program becomes a set of objects sending messages to each other.

This unit is about that idea — the four features the syllabus names (class, object, inheritance, polymorphism), why the software industry moved to it, and where it is used.

What the exam asks from this unit

This is a 10-hour unit but it is mostly theory. Group B almost always has one of: define class and object with an example, differentiate between procedural and object-oriented programming, explain any four features of OOP.

Group C asks you to write a program with a class, a constructor, inheritance and function overloading/overriding, so learn one complete program template by heart. All example code here is C++, the language NEB uses for OOP.

5.1 Programming paradigms: procedural, structural and object oriented

A programming paradigm is a style of organising a program — a way of thinking about what a program is. Three paradigms matter for this course.

Procedural (or monolithic-then-procedural) programming. The program is a sequence of instructions grouped into procedures (functions). Data is usually global, so any function can read or change it.

Design is top-down: split the job into functions, then split those into smaller functions. FORTRAN (1957), COBOL (1959) and C (1972) are procedural languages.

Structured programming. This is procedural programming with discipline added.

It insists that every algorithm be built from only three control structures — sequence, selection (if, switch) and iteration (for, while) — each with a single entry and a single exit, and that goto be avoided.

Dijkstra's 1968 letter "Go To Statement Considered Harmful" started it. A structured program is divided into independent modules that communicate through parameters and return values instead of global variables.

C is the classic structured language, and everything you did in Unit 4 was structured programming.

Object-oriented programming. The program is organised around the data, not the actions.

Data and the functions that operate on it are wrapped into a single unit (an object); outside code can only reach the data through the functions the object chooses to publish.

Design is bottom-up: first identify the objects in the problem, then give them behaviour.

Simula 67 (Dahl and Nygaard, 1967) was the first object-oriented language; Smalltalk (Xerox PARC, 1970s) made the ideas famous; C++ (Bjarne Stroustrup, Bell Labs — "C with Classes" in 1979, renamed C++ in 1983, released 1985), Java (1995), Python, C# and Kotlin are the languages in use today.

figure
Figure 1. Left: procedural code — functions reach into shared global data, so a change in the data affects every function. Right: object-oriented code — data is sealed inside the object and reached only through its public methods.

The same tiny job — the area of a rectangle — written both ways makes the difference concrete. First procedural C:

#include <stdio.h>

struct Rect { float len, bre; };          /* data only */

float area(struct Rect r) {               /* function kept separate */
    return r.len * r.bre;
}

int main() {
    struct Rect r = {12.5f, 8.0f};
    printf("Area = %.2f sq. m\n", area(r));
    return 0;
}

Output:

Area = 100.00 sq. m

Nothing stops another part of the program from writing r.len = -5;. Now the object-oriented version in C++:

#include <iostream>
using namespace std;

class Rect {
    float len, bre;                       // data: private, hidden
  public:
    Rect(float l, float b) {              // constructor
        len = l; bre = b;
    }
    float area() {                        // behaviour: bundled with the data
        return len * bre;
    }
};

int main() {
    Rect r(12.5, 8.0);
    cout << "Area = " << r.area() << " sq. m" << endl;
    return 0;
}

Output:

Area = 100 sq. m

r.len is now inaccessible from main(); the only way in is the constructor, and the only way out is area().

Feature Procedural / structured Object-oriented
Basic unit function (procedure) class / object
Design direction top-down bottom-up
Data handling mostly global, shared private inside objects
Data security weak — any function can change data strong — access specifiers protect data
Code reuse by calling functions again by inheritance, plus functions
Adding a new feature often means editing existing functions usually means adding a new class
Real-world modelling poor direct (one object per real thing)
Suitable for small and medium programs large, long-lived, multi-programmer software
Examples C, FORTRAN, COBOL, Pascal C++, Java, Python, C#, Kotlin
"Structural" is not a third kind of language

The syllabus word structural means structured programming, which is a disciplined form of procedural programming — not a separate family. C is both procedural and structured. Do not write that C is "structural but not procedural".

5.2 Features of OOP: class, object, polymorphism and inheritance

5.2.1 Class and object

Class and object

A class is a user-defined data type that binds together data members (attributes) and member functions (methods) under one name. It is only a blueprint — writing a class allocates no memory for data.

An object is an instance of a class: a real variable of that class type, with its own copy of the data members, created in memory at run time.

Class is to object what struct Student is to a particular student variable — except that a class also carries the functions. In Rect r(12.5, 8.0); the class is Rect and the object is r.

figure
Figure 2. One class, many objects. The class fixes what attributes exist; each object stores its own values for them.

The general form of a class in C++ is:

class ClassName {
  private:                 // default; hidden from outside
    // data members
  protected:               // visible to derived classes only
    // data members
  public:                  // the interface
    ClassName();           // constructor
    ~ClassName();          // destructor
    // member functions
};                         // note the semicolon

A constructor is a member function with the same name as the class, with no return type, called automatically when an object is created; it is used to initialise the data members.

A destructor (~ClassName()) is called automatically when the object is destroyed. Here is a full class with both kinds of constructor, a validating setter and a static member:

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

class Student {
    // ---- private data members: hidden state of the object ----
    string name;
    int    roll;
    int    marks[3];

  public:
    static int count;                       // one copy shared by all objects

    Student() {                             // default constructor
        name = "not admitted"; roll = 0;
        marks[0] = marks[1] = marks[2] = 0;
        count++;
    }
    Student(string n, int r, int m1, int m2, int m3) {   // parameterised
        name = n; roll = r;
        marks[0] = m1; marks[1] = m2; marks[2] = m3;
        count++;
    }
    int total() const { return marks[0] + marks[1] + marks[2]; }

    double percentage() const { return total() / 3.0; }

    char grade() const {
        double p = percentage();
        if (p >= 80)      return 'A';
        else if (p >= 60) return 'B';
        else if (p >= 40) return 'C';
        else              return 'F';
    }
    void setMarks(int i, int m) {            // controlled write access
        if (i >= 0 && i < 3 && m >= 0 && m <= 100) marks[i] = m;
        else cout << "Invalid mark rejected" << endl;
    }
    void display() const {
        cout << setw(5) << roll << setw(16) << name << setw(7) << total()
             << setw(9) << fixed << setprecision(2) << percentage()
             << setw(7) << grade() << endl;
    }
};

int Student::count = 0;                      // static member defined outside

int main() {
    Student s1("Sita Rai", 1, 78, 85, 92);
    Student s2("Bikash Thapa", 2, 55, 61, 48);

    cout << setw(5) << "Roll" << setw(16) << "Name" << setw(7) << "Total"
         << setw(9) << "Percent" << setw(7) << "Grade" << endl;
    s1.display();
    s2.display();

    s2.setMarks(1, 105);                     // rejected by the setter
    cout << "Students created = " << Student::count << endl;
    return 0;
}

Output (compiled with g++ student.cpp -o student):

 Roll            Name  Total  Percent  Grade
    1        Sita Rai    255    85.00      A
    2    Bikash Thapa    164    54.67      C
Invalid mark rejected
Students created = 2

5.2.2 Data encapsulation and data hiding

Encapsulation is the wrapping of data and the functions that act on it into one unit — the class.

The consequence is data hiding: because name, roll and marks are private, no statement outside the class can read or write them directly. s1.marks[0] = 999; is a compile-time error.

All traffic goes through the public interface, which can check it — that is why setMarks(1, 105) printed a rejection instead of storing an impossible mark.

Access specifier Same class Derived class Outside the class
private yes no no
protected yes yes no
public yes yes yes

figure
Figure 3. What each access specifier lets through. Code outside the class reaches only the public interface; a derived class also sees the protected part; nothing outside reaches the private part.

5.2.3 Abstraction

Abstraction means showing only the essential features and hiding the internal detail. You call s1.percentage() without knowing whether the marks are stored in an array, three separate variables or a file.

In C++, abstraction is achieved with the class interface and, at a higher level, with abstract classes — classes containing at least one pure virtual function (virtual double earning() const = 0;), which cannot be instantiated and exist only to fix the interface that derived classes must provide.

Encapsulation vs abstraction in one line

Encapsulation is how it is hidden (bundling + access specifiers); abstraction is what the user is shown (the interface). Give this one line and one example in the exam and the mark is yours.

5.2.4 Inheritance

Inheritance

Inheritance is the mechanism by which one class (the derived, child or sub-class) acquires the data members and member functions of another class (the base, parent or super-class), and may then add its own members or redefine inherited ones.

It gives reusability and expresses an "is-a" relationship: a Teacher is a Person.

class Teacher : public Person {   // public inheritance
    // extra members
};

Five forms of inheritance are examinable:

Type Structure Example
Single one base, one derived Person → Student
Multilevel derived class becomes a base Person → Student → HostelStudent
Multiple one derived, two or more bases Student + Athlete → SportsScholar
Hierarchical one base, many derived Person → Student, Teacher, Staff
Hybrid a combination of the above multilevel + multiple together

figure
Figure 4. The five forms of inheritance. An arrow points from the derived class to its base class, as in UML.

When an object of a derived class is created, the base constructor runs first, then the derived constructor; destructors run in the exact reverse order. This order is a favourite one-mark question.

figure
Figure 5. Order of constructor and destructor calls for a derived object. Construction goes base-first, destruction derived-first.

5.2.5 Polymorphism

Polymorphism

Polymorphism (Greek: many forms) is the ability of one name, operator or message to behave differently depending on the type or number of the data it is used with.

C++ provides compile-time polymorphism through function overloading and operator overloading, and run-time polymorphism through virtual functions and overriding.

Compile-time (static) polymorphism. Several functions share one name but differ in the number or type of parameters; the compiler picks the right one from the call:

#include <iostream>
using namespace std;

// compile-time polymorphism: one name, three different signatures
int  volume(int s)                  { return s * s * s; }          // cube
int  volume(int l, int b, int h)    { return l * b * h; }          // cuboid
double volume(double r, double h)   { return 3.1416 * r * r * h; } // cylinder

int main() {
    cout << "Cube      : " << volume(4)          << endl;
    cout << "Cuboid    : " << volume(5, 4, 3)    << endl;
    cout << "Cylinder  : " << volume(2.0, 7.0)   << endl;
    return 0;
}

Output:

Cube      : 64
Cuboid    : 60
Cylinder  : 87.9648

Run-time (dynamic) polymorphism. A base-class pointer holds a derived-class object, and the function that actually runs is decided while the program is running.

The base function must be declared virtual, otherwise the compiler binds the call early and the base version runs:

#include <iostream>
using namespace std;

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

class Derived : public Base {
  public:
    void show()          { cout << "Derived::show" << endl; }
    void draw() override { cout << "Derived::draw" << endl; }
};

int main() {
    Derived d;
    Base *bp = &d;        // base pointer holding a derived object
    bp->show();           // early (compile-time) binding  -> Base
    bp->draw();           // late  (run-time)  binding     -> Derived
    return 0;
}

Output:

Base::show  (not virtual)
Derived::draw

figure
Figure 6. Compile-time polymorphism resolves the call by signature before the program runs; run-time polymorphism resolves it from the actual object type while the program runs.

Function overloading Function overriding
Where same class (or scope) base class and derived class
Signature must differ must be identical
Binding early, at compile time late, at run time
Keyword needed none virtual in the base class
Type of polymorphism compile-time (static) run-time (dynamic)

5.2.6 Message passing and dynamic binding

Objects do not call each other's code directly; they send messages — a message is the name of a member function plus its arguments, sent to a named object (s1.display()).

Dynamic binding (late binding) means the code associated with a message is not known until run time, which is exactly what makes p[i]->display() behave differently for each element of the array below.

Putting every feature into one program gives the classic Group C answer:

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

// ---------------- base class ----------------
class Person {
  protected:
    string name;
    int    age;
  public:
    Person(string n, int a) : name(n), age(a) {
        cout << "Person constructor: " << name << endl;
    }
    virtual void display() const {                 // virtual -> late binding
        cout << left << setw(14) << name << setw(5) << age;
    }
    virtual double earning() const = 0;            // pure virtual: abstract class
    virtual ~Person() { cout << "Person destructor: " << name << endl; }
};

// ---------------- derived class 1 ----------------
class Teacher : public Person {
    string subject;
    double salary;
  public:
    Teacher(string n, int a, string s, double sal)
        : Person(n, a), subject(s), salary(sal) {
        cout << "Teacher constructor: " << name << endl;
    }
    void display() const override {
        Person::display();                          // reuse the base version
        cout << setw(10) << "Teacher" << setw(12) << subject
             << "Rs " << fixed << setprecision(2) << earning() << endl;
    }
    double earning() const override { return salary; }
};

// ---------------- derived class 2 ----------------
class Student : public Person {
    string faculty;
    double scholarship;
  public:
    Student(string n, int a, string f, double sc)
        : Person(n, a), faculty(f), scholarship(sc) {
        cout << "Student constructor: " << name << endl;
    }
    void display() const override {
        Person::display();
        cout << setw(10) << "Student" << setw(12) << faculty
             << "Rs " << fixed << setprecision(2) << earning() << endl;
    }
    double earning() const override { return scholarship; }
};

int main() {
    Person *p[3];                                   // base-class pointers
    p[0] = new Teacher("Ram Sharma", 41, "Computer", 48500);
    p[1] = new Student("Sita Rai",   18, "Science",   1200);
    p[2] = new Teacher("Gita Magar", 35, "Maths",    52000);

    cout << "\n--- Staff and student list ---" << endl;
    double sum = 0;
    for (int i = 0; i < 3; i++) {
        p[i]->display();                            // same call, different code
        sum += p[i]->earning();
    }
    cout << "Total monthly payout = Rs " << sum << "\n" << endl;

    for (int i = 0; i < 3; i++) delete p[i];        // virtual destructor runs
    return 0;
}

Output:

Person constructor: Ram Sharma
Teacher constructor: Ram Sharma
Person constructor: Sita Rai
Student constructor: Sita Rai
Person constructor: Gita Magar
Teacher constructor: Gita Magar

--- Staff and student list ---
Ram Sharma    41   Teacher   Computer    Rs 48500.00
Sita Rai      18   Student   Science     Rs 1200.00
Gita Magar    35   Teacher   Maths       Rs 52000.00
Total monthly payout = Rs 101700.00

Person destructor: Ram Sharma
Person destructor: Sita Rai
Person destructor: Gita Magar

A class diagram is how this design is drawn on paper. UML notation puts the class name, then attributes, then methods in one box, marks private members with - and public with +, uses a hollow triangle arrow for inheritance and a plain line for association.

figure
Figure 7. UML class diagram for the program above: `Teacher` and `Student` inherit from the abstract class `Person` (hollow triangle), and a `School` is associated with many of each.

OOP principle What it means Example from this chapter
Class blueprint of data + methods class Student { ... };
Object an instance with its own data Student s1("Sita Rai", 1, 78, 85, 92);
Encapsulation data + methods in one unit marks[3] is private, reached via setMarks()
Data hiding outsiders cannot touch the data s1.marks[0] = 999; fails to compile
Abstraction show the interface, hide the detail percentage() hides how marks are stored
Inheritance derived class reuses a base class class Teacher : public Person
Polymorphism one name, many behaviours volume() overloaded; earning() overridden
Dynamic binding function chosen at run time p[i]->display() inside the loop
Message passing calling a method on an object s1.display()
Worked example 5.1 — class with a calculation

Problem. Write a C++ class Employee with a parameterised constructor that stores a name and a basic salary. Add member functions to compute a 20 % allowance, the gross pay, 1 % social-security tax on the gross, and the net pay.

Show the payslip for Hari Bahadur, whose basic salary is Rs 35,000.

Solution.

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

class Employee {
    string name;
    double basic;
  public:
    Employee(string n, double b) : name(n), basic(b) {}
    double allowance() const { return 0.20 * basic; }        // 20% of basic
    double gross()     const { return basic + allowance(); }
    double tax()       const { return 0.01 * gross(); }      // 1% social security
    double net()       const { return gross() - tax(); }
    void payslip() const {
        cout << "Employee : " << name << endl;
        cout << fixed << setprecision(2);
        cout << "  Basic     Rs " << setw(10) << basic      << endl;
        cout << "  Allowance Rs " << setw(10) << allowance() << endl;
        cout << "  Gross     Rs " << setw(10) << gross()     << endl;
        cout << "  Tax (1%)  Rs " << setw(10) << tax()       << endl;
        cout << "  Net pay   Rs " << setw(10) << net()       << endl;
    }
};

int main() {
    Employee e("Hari Bahadur", 35000);
    e.payslip();
    return 0;
}

Checking the arithmetic by hand: allowance = 0.20 \times 35000 = 7000, gross = 35000 + 7000 = 42000, tax = 0.01 \times 42000 = 420, net = 42000 - 420 = 41580. The program prints exactly that:

Employee : Hari Bahadur
  Basic     Rs   35000.00
  Allowance Rs    7000.00
  Gross     Rs   42000.00
  Tax (1%)  Rs     420.00
  Net pay   Rs   41580.00
Worked example 5.2 — predict the output

Problem. What does this program print, and why?

class A {
  public:
    A()              { cout << "A "; }
    void f()         { cout << "A::f "; }
    virtual void g() { cout << "A::g "; }
};
class B : public A {
  public:
    B()              { cout << "B "; }
    void f()         { cout << "B::f "; }
    void g()         { cout << "B::g "; }
};
int main() { A *p = new B(); p->f(); p->g(); }

Solution. new B() first runs the base constructor A(), then B(), so the first output is A B. f() is not virtual, so p->f() is bound at compile time using the pointer's type A* and prints A::f. g() is virtual, so the call is bound at run time using the object's real type B and prints B::g.

Full output: A B A::f B::g

Three errors that cost marks every year
  1. Forgetting the semicolon after the closing brace of a class.
  2. Writing a return type for a constructor (void Student() is not a constructor).
  3. Expecting a base pointer to call the derived function without virtual — it will not. Overriding needs virtual in the base class.

5.3 Advantages of OOP

Eight advantages, each explained in full.

1. Reusability. Through inheritance a tested class can be extended instead of rewritten, and a class can be packed into a library for others to use. A Person class written once can serve Student, Teacher and Staff. This saves time and reduces new errors.

2. Data security. Access specifiers make the data private, so unrelated code cannot corrupt it. A bank account class can allow the balance to change only through deposit() and withdraw(). Data hiding therefore protects the object from misuse.

3. Easier maintenance. A bug in percentage() can only be caused by code inside Student, so the search is limited to one class, not the whole program. Each class can be corrected or improved without touching the others. Large programs remain manageable over many years.

4. Modelling power. Objects map one-to-one onto real things such as a student, an invoice or a bus route. The design is therefore natural and easy to discuss with the customer. Analysis, design and coding use the same ideas.

5. Extensibility. A new class can be added without changing existing code. Adding a Staff class to the payroll program needs no change in main(), because main() talks only to Person*. The program grows by addition, not by modification.

6. Modular team work. Different programmers can own different classes and agree only on the public interfaces. A team of five can build five classes in parallel and join them at the end. This speeds up big projects.

7. Polymorphism and flexibility. One function name or one message can do different jobs for different objects. A loop that calls area() for every shape works for all the shapes, even those added later. The code becomes shorter and clearer.

8. Message passing. Objects communicate by sending messages, that is, by calling member functions. This makes the communication of a large system explicit and easy to trace. Each object remains independent of how others work inside.

The costs are real too, and examiners accept them as "disadvantages": programs are larger and need more memory, execution can be slightly slower because of dynamic binding, the design phase takes longer, and the paradigm is overkill for a 20-line calculation.

5.4 Application of OOP

Application area Why OOP fits Typical tools
Graphical user interfaces every widget is an object with properties and events Qt, Android SDK, JavaFX
Simulation and modelling the original purpose of Simula — each entity is an object traffic, weather, queue simulations
Computer games and graphics player, enemy, bullet all inherit from a common base Unity (C#), Unreal (C++)
Mobile applications activity/view classes are extended by the developer Kotlin, Swift
Web frameworks request, model, controller classes Laravel (PHP), Django (Python)
Operating systems and device drivers device classes with a common interface C++ subsystems in Windows, macOS
CAD/CAM and design software geometric shapes form a natural class hierarchy AutoCAD, SolidWorks
Database and ORM layers a table row becomes an object Hibernate, Eloquent
Banking, ERP and payroll software account, customer, transaction objects; auditability Java/C# enterprise systems
AI and data-science libraries model classes with a shared fit/predict interface scikit-learn, TensorFlow

Eight applications explained.

1. Graphical user interfaces. Every window, button and text box is an object with properties (colour, size) and events (click). Frameworks such as Qt and the Android SDK are built from such classes. A programmer builds a new screen by extending them.

2. Simulation and modelling. The first object-oriented language, Simula, was made to simulate real systems. Each vehicle, patient or customer in a queue is an object with its own state. Traffic and bank-queue simulations are typical.

3. Computer games. Player, enemy and bullet inherit from one base class and are drawn and moved by the same loop. Engines such as Unity and Unreal use this design. New characters are added by creating new classes.

4. Mobile applications. Apps for Android (Kotlin or Java) and iPhone (Swift) are written by extending activity and view classes. Wallet and ticketing apps used in Nepal are built this way.

5. Web frameworks. Frameworks such as Laravel and Django model requests, data and controllers as classes. A college website can add a new page type by adding a new class.

6. Operating systems and device drivers. Devices such as printers and disks are objects that share a common interface. The system treats all of them in the same way, whatever the hardware.

7. CAD and design software. Lines, circles and other shapes form a natural class hierarchy, and each knows how to draw and measure itself. Programs such as AutoCAD work like this.

8. Banking, ERP and payroll software. Account, customer and transaction are objects with clear rules and an audit trail. Enterprise systems in banks are normally written in Java or C#. The same design supports AI libraries and database layers.

Worked example 5.3 — choosing the paradigm

Problem. A Kathmandu school wants(a) a program to convert a temperature from Celsius to Fahrenheit for a physics class, and(b) a school management system holding students, teachers, fees, attendance and exam results, to be maintained for the next ten years by different programmers. Which paradigm suits each, and why?

Solution. (a) Procedural/structured C is the right choice. The task is a single formula, F = \frac{9}{5}C + 32; one function is enough, and a class would add code without adding safety.

(b) Object-oriented design is the right choice.

There are many real-world entities (Student, Teacher, Fee, Attendance, Exam) with shared attributes, so a Person base class removes duplication; the data is sensitive, so private members with validating setters protect it; the system will be extended for ten years, so adding a class must not break existing code; and several programmers can own separate classes at once.

photograph
(a) Lego bricks: one design (class) gives many bricks (objects)
diagram
(b) Polymorphism: one call, three results
Plate 5.P. Object-oriented programming builds a class once and then makes as many objects as needed, as one brick mould makes many bricks. (a) A heap of Lego bricks. (b) Rect, Circle and Tri inherit from Shape and each overrides area(). The same call s.area() therefore runs a different method for each object and returns 12.00, 12.57 and 12.00. This is polymorphism: the caller does not need to know the type. Inheritance saved the repeated code, encapsulation keeps w, h and r inside each object, and a new shape can be added without changing the loop that calls area().Photo credits: (a) Ralf Roletschek, GFDL 1.2.

Chapter summary

  • A paradigm is a style of organising a program: procedural (functions on shared data), structured (procedural with only sequence/selection/iteration and modules), object-oriented (data and behaviour bundled into objects).
  • A class is a blueprint binding data members and member functions; an object is an instance of a class with its own copy of the data.
  • A constructor has the class's name, no return type, and runs automatically at creation; the destructor ~Class() runs at destruction. In inheritance, constructors run base→derived and destructors derived→base.
  • Encapsulation bundles data with methods; data hiding follows from private; abstraction exposes only the interface. private = class only, protected = class + derived, public = everywhere.
  • Inheritance (single, multilevel, multiple, hierarchical, hybrid) gives reuse and expresses "is-a"; the derived class inherits with class D : public B.
  • Polymorphism is compile-time (function/operator overloading, early binding) or run-time (overriding a virtual function through a base pointer, late binding).
  • Advantages: reusability, data security, easy maintenance, real-world modelling, extensibility, parallel team work. Costs: bigger code, slower dynamic dispatch, longer design phase.
  • OOP is used for GUIs, simulation, games, mobile apps, web frameworks, operating systems, CAD, ORMs, banking systems and ML libraries.

Practice questions

Group A — Multiple choice (1 mark each)

  1. Which of the following is not a feature of object-oriented programming? [1]ainheritancebpolymorphismcencapsulationdglobal data sharing
  2. A class is best described as [1]aan instance of an objectba blueprint for objectsca block of memoryda library function
  3. Which member function is called automatically when an object is created? [1]adestructorbfriend functioncconstructordmain()
  4. Members declared protected in a base class are accessible in [1]athe base class onlybthe base and derived classesceverywherednowhere
  5. Function overloading is an example of [1]arun-time polymorphismbcompile-time polymorphismcinheritancedencapsulation
  6. class C : public A, public B is an example of [1]asingle inheritancebmultilevel inheritancecmultiple inheritancedhierarchical inheritance
Answers to Group A

1. (d) — OOP hides data rather than sharing it globally.

2. (b) — a class allocates no data memory; objects do.

3. (c) — the constructor; it has the class name and no return type.

4. (b) — protected is private to the outside world but visible to children.

5. (b) — the compiler picks the version from the signature.

6. (c) — one derived class with two base classes.

Group B — Short answer (5 marks each)

  1. Define class and object. Write a C++ class Circle with a constructor and a member function that returns the area, and create one object of it. [5]
  2. Differentiate between procedural and object-oriented programming on any five points. [5]
  3. What is inheritance? Explain any three types with a diagram. [5]
  4. Distinguish between function overloading and function overriding with one example of each. [5]
  5. State any five advantages of OOP and any two of its disadvantages. [5]
Answers to Group B

1. Definitions as in §5.2.1. Program:

#include <iostream>
using namespace std;
class Circle {
    double r;
  public:
    Circle(double radius) { r = radius; }
    double area() { return 3.1416 * r * r; }
};
int main() {
    Circle c(7.0);
    cout << "Area = " << c.area() << endl;   // prints Area = 153.938
    return 0;
}

Check: 3.1416 \times 7^2 = 3.1416 \times 49 = 153.9384, so the output is Area = 153.938 (cout shows six significant figures by default).

2.

Point Procedural programming Object-oriented programming
Basic unit Function (procedure) Class and object
Design direction Top-down Bottom-up
Data handling Data are global and shared by functions Data are hidden inside objects
Security Weak, anyone can change the data Strong, through access specifiers
Reuse Copy and modify functions Inheritance and libraries
Suitability Small tasks and calculations Large, long-lived systems
Examples C, Pascal, FORTRAN C++, Java, Python

In procedural programming the program is a list of steps and functions that act on shared data, so a change in a data layout can break many functions.

In object-oriented programming the data and the functions that use them are packed together in a class, so the program is organised around the things it models.

A single formula such as converting Celsius to Fahrenheit needs only a procedure, but a school management system with students, teachers and fees is much better as a set of objects.

3. Inheritance is the property by which a derived class acquires the members of a base class, giving reuse and an "is-a" relationship (a Teacher is a Person).

Three types: (i) Single inheritance: one derived class from one base class, A → B; a Student derived from Person.

(ii) Multilevel inheritance: a chain of derivation, A → B → C; Person → Student → GraduateStudent; each level inherits all members of the levels above it.

(iii) Hierarchical inheritance: one base class with several derived classes; Person is the base of Student, Teacher and Staff. Multiple inheritance (A, B → C) lets a class have two bases and is also available in C++.

In C++ the syntax is class Teacher : public Person.

(Draw the figure of section 5.2.4 with arrows from derived to base.) Inheritance saves coding time, makes programs shorter and lets new classes be added without changing old ones, but a deep hierarchy can become hard to follow.

4. Function overloading means several functions with the same name in the same scope, but with different parameter lists (number or type); the compiler chooses one at compile time (early binding).

Example volume(int a) for a cube and volume(int l, int b, int h) for a cuboid. Function overriding means a derived class redefines a function of its base class with the same signature; with the virtual keyword the call is resolved at run time (late binding).

Example Person::earning() is overridden by Teacher::earning().

Basis Overloading Overriding
Classes Same class Base and derived classes
Signature Different Identical
Binding Compile time (early) Run time (late, with virtual)
Type of polymorphism Compile-time Run-time
Purpose Same job on different data Specialised behaviour in a derived class

Overloading makes a program easy to read because one name does related jobs, and overriding lets a base-class pointer call the correct version of a function for each kind of object.

5. Five advantages of OOP: (i) Reusability: inheritance lets tested classes be extended instead of rewritten. (ii) Data security: private data are reachable only through public functions.

(iii) Easier maintenance: a fault is limited to one class. (iv) Real-world modelling: objects match real things, so the design is natural. (v) Extensibility: new classes can be added without changing existing code.

Other advantages are modular teamwork and message passing.

Two disadvantages: (i) programs are larger and need more memory and design time; (ii) execution can be slightly slower because of dynamic binding, and the paradigm is too heavy for very small programs.

For a school management system of many years, the advantages are far greater than the disadvantages.

Group C — Long answer (8 marks each)

  1. Explain the four features of OOP named in the syllabus — class, object, inheritance and polymorphism — giving a short C++ code fragment for each. [8]
  2. Write a complete C++ program that defines a base class Person with name and age, derives Teacher (with subject and salary) and Student (with faculty and scholarship) from it, uses a virtual function to display the details of each, and prints the total monthly payment for an array of three base-class pointers. [8]
Answers to Group C

1. Definition + fragment for each of the four, as in §5.2: the class/object fragment from Student, class Teacher : public Person for inheritance, the overloaded volume() and the virtual earning() for the two kinds of polymorphism.

One mark for each definition, one for each fragment.

2. The complete program and its verified output are given at the end of §5.2.6.

Marking usually goes: class definitions with correct access specifiers (2), constructors with an initialisation list or assignment (2), virtual function correctly overridden (2), array of base pointers and the loop (1), correct total and output format (1).

The total for the data used is Rs 48,500 + Rs 1,200 + Rs 52,000 = Rs 1,01,700.

Group D — Long answer (10 marks each), with full model answers

  1. Explain the features of OOP: class, object, encapsulation, abstraction, inheritance and polymorphism. [10]
  2. Differentiate between procedural and object-oriented programming. Explain the advantages and disadvantages of OOP. [10]
  3. Define polymorphism. Explain its types with examples and compare overloading with overriding. [10]

Model answer D1: features of OOP (10 marks)

Introduction. Object-oriented programming (OOP) is a programming paradigm in which a program is built from objects that combine data and the functions that act on the data. C++, Java and Python support it. Its main features are as follows.

  1. Class: a user-defined type or blueprint that describes the data (attributes) and the functions (methods) common to a group of things. class Student { ... };
  2. Object: an instance of a class that occupies memory and has its own values. Student s1; creates one student object; many objects can be made from one class.
  3. Encapsulation and data hiding: wrapping data and functions in one unit, the class, and restricting access with private, protected and public. The balance of an account is private and changes only through public functions.
  4. Abstraction: showing only the essential features and hiding the details. A driver uses the steering wheel and pedals without knowing the engine; a class shows its public interface and hides its code.
  5. Inheritance: a derived class acquires the members of a base class, giving reuse and an "is-a" relationship: class Teacher : public Person. Types are single, multilevel, multiple, hierarchical and hybrid.
  6. Polymorphism: one name, many forms. Compile-time polymorphism uses function and operator overloading; run-time polymorphism uses virtual functions and overriding.
  7. Message passing and dynamic binding: objects communicate by calling member functions, and the function to execute can be chosen at run time.
class Person { public: virtual double earning() { return 0; } };
class Teacher : public Person {          // inheritance
    double salary;                       // data hiding (private by default)
  public:
    Teacher(double s) { salary = s; }
    double earning() { return salary; }  // overriding (run-time polymorphism)
};
Feature One-line meaning Keyword in C++
Class Blueprint class
Object Instance Student s1;
Encapsulation Data and functions in one unit private, public
Inheritance Reuse of a base class : public Base
Polymorphism One name, many forms virtual, overloading

Conclusion. These features together make programs secure, reusable and easy to extend, which is why large software in banks and mobile apps is written in an object-oriented way.

Model answer D2: procedural against object-oriented, and the merits (10 marks)

Introduction. A programming paradigm is a style of building programs. In procedural programming (C, Pascal) the program is a sequence of procedures that act on shared data.

In object-oriented programming (C++, Java) the program is a set of objects that hold their own data and behaviour.

Point Procedural Object-oriented
Basic unit Function Class and object
Design Top-down Bottom-up
Data Global, shared Hidden inside objects
Security Weak Strong
Reuse Copy functions Inheritance
Maintenance Difficult in large programs Easier, by class
Suitable for Small, simple programs Large, long-lived systems

Advantages of OOP. (1) Reusability through inheritance; (2) data security by hiding; (3) easier maintenance; (4) natural modelling of real things; (5) extensibility without changing old code; (6) modular teamwork; (7) polymorphism; (8) message passing.

Disadvantages of OOP. Larger programs and more memory; slightly slower execution because of dynamic binding; longer design time; and it is unnecessary for very small programs.

Example. A Celsius-to-Fahrenheit converter needs only one function and is best written procedurally, whereas a school management system with students, teachers, fees and attendance, to be maintained for ten years by several programmers, is best written with classes.

Conclusion. Neither paradigm is always better; OOP is the right choice when a program is large, changes often and models many real-world things.

Model answer D3: polymorphism (10 marks)

Introduction. Polymorphism means "many forms": the same name or operator behaves in different ways depending on the data or the object it is used with. It is one of the four pillars of OOP.

Types.

  1. Compile-time (static) polymorphism: the function to call is decided by the compiler. It is achieved by function overloading (same name, different parameters) and operator overloading (giving + a meaning for a user class). Example: volume(int a) for a cube and volume(int l, int b, int h) for a cuboid.
  2. Run-time (dynamic) polymorphism: the function is chosen while the program runs, through a base-class pointer and a virtual function. Example: a Person* that points to a Teacher calls Teacher::earning(), and the same pointer pointing to a Staff calls Staff::earning().
Person* p[2] = { new Teacher(52000), new Staff(48500) };
for (int i = 0; i < 2; i++) cout << p[i]->earning() << endl;   // each object answers in its own way
Basis Overloading Overriding
Place Same class Base and derived class
Signature Different Same
Binding Early (compile time) Late (run time), needs virtual
Purpose Same name for related jobs Special behaviour in a derived class

Advantages. Shorter and clearer code, easy extension (a new derived class works with old code), and a single interface for many kinds of object.

Conclusion. Polymorphism lets a program treat different objects uniformly while each one behaves correctly, and that is why a payroll loop does not need to change when a new kind of employee is added.

Practise more: Computer Science question bank