2082

BIT153 · TU past paper

Object Oriented Programming 2082 question paper

The complete TU 2082 exam paper for Object Oriented Programming (BIT153), all 12 questions with solved model answers written to the mark scheme.

Tap a question to open its answer.

  1. 110 marksConstructor overloadingAnswer

    Write a program to create a class Student with data members id, name, and marks. Define constructors to initialize data members and demonstrate constructor overloading. Implement member functions to read students details, display them and calculate average marks.[10]

    Constructor Overloading with Student Class

    Concept

    Constructor overloading means defining multiple constructors in the same class with different parameter lists. The compiler selects the appropriate constructor based on the arguments passed during object creation.


    Complete C++ Program

    #include <iostream>
    #include <string>
    using namespace std;
    
    class Student {
    private:
        int id;
        string name;
        float marks[5];   // stores marks of 5 subjects
        int numSubjects;
    
    public:
        // -----------------------------------------------
        // Constructor 1: Default Constructor
        // Initializes data members with default values
        // -----------------------------------------------
        Student() {
            id = 0;
            name = "Unknown";
            numSubjects = 5;
            for (int i = 0; i < numSubjects; i++) {
                marks[i] = 0.0;
            }
            cout << "Default constructor called." << endl;
        }
    
        // -----------------------------------------------
        // Constructor 2: Parameterized Constructor
        // Initializes id and name; marks set to 0
        // -----------------------------------------------
        Student(int i, string n) {
            id = i;
            name = n;
            numSubjects = 5;
            for (int j = 0; j < numSubjects; j++) {
                marks[j] = 0.0;
            }
            cout << "Parameterized constructor (id, name) called." << endl;
        }
    
        // -----------------------------------------------
        // Constructor 3: Fully Parameterized Constructor
        // Initializes all data members including marks
        // -----------------------------------------------
        Student(int i, string n, float m[], int num) {
            id = i;
            name = n;
            numSubjects = num;
            for (int j = 0; j < numSubjects; j++) {
                marks[j] = m[j];
            }
            cout << "Fully parameterized constructor called." << endl;
        }
    
        // -----------------------------------------------
        // Member Function: Read student details
        // -----------------------------------------------
        void readDetails() {
            cout << "\nEnter Student ID   : ";
            cin >> id;
            cout << "Enter Student Name : ";
            cin.ignore();
            getline(cin, name);
            cout << "Enter marks for " << numSubjects << " subjects:" << endl;
            for (int i = 0; i < numSubjects; i++) {
                cout << "  Subject " << (i + 1) << " : ";
                cin >> marks[i];
            }
        }
    
        // -----------------------------------------------
        // Member Function: Display student details
        // -----------------------------------------------
        void displayDetails() {
            cout << "\n--- Student Details ---" << endl;
            cout << "ID     : " << id << endl;
            cout << "Name   : " << name << endl;
            cout << "Marks  : ";
            for (int i = 0; i < numSubjects; i++) {
                cout << marks[i];
                if (i < numSubjects - 1) cout << ", ";
            }
            cout << endl;
            cout << "Average: " << calculateAverage() << endl;
            cout << "-----------------------" << endl;
        }
    
        // -----------------------------------------------
        // Member Function: Calculate average marks
        // -----------------------------------------------
        float calculateAverage() {
            float sum = 0.0;
            for (int i = 0; i < numSubjects; i++) {
                sum += marks[i];
            }
            return sum / numSubjects;
        }
    };
    
    // -----------------------------------------------
    // Main Function: Demonstrates constructor overloading
    // -----------------------------------------------
    int main() {
        cout << "========================================" << endl;
        cout << "   Constructor Overloading Demo         " << endl;
        cout << "========================================" << endl;
    
        // Using Default Constructor
        cout << "\n[Object 1: Default Constructor]" << endl;
        Student s1;
        s1.readDetails();
        s1.displayDetails();
    
        // Using Parameterized Constructor (id and name only)
        cout << "\n[Object 2: Parameterized Constructor (id, name)]" << endl;
        Student s2(102, "Ram Sharma");
        s2.readDetails();
        s2.displayDetails();
    
        // Using Fully Parameterized Constructor
        cout << "\n[Object 3: Fully Parameterized Constructor]" << endl;
        float m[] = {78.5, 85.0, 90.0, 72.5, 88.0};
        Student s3(103, "Sita Thapa", m, 5);
        s3.displayDetails();   // no need to read; already initialized
    
        return 0;
    }
    

    Sample Output

    ========================================
       Constructor Overloading Demo
    ========================================
    
    [Object 1: Default Constructor]
    Default constructor called.
    
    Enter Student ID   : 101
    Enter Student Name : Hari Bahadur
    Enter marks for 5 subjects:
      Subject 1 : 75
      Subject 2 : 80
      Subject 3 : 65
      Subject 4 : 90
      Subject 5 : 70
    
    --- Student Details ---
    ID     : 101
    Name   : Hari Bahadur
    Marks  : 75, 80, 65, 90, 70
    Average: 76
    -----------------------
    
    [Object 2: Parameterized Constructor (id, name)]
    Parameterized constructor (id, name) called.
    ...
    
    [Object 3: Fully Parameterized Constructor]
    Fully parameterized constructor called.
    
    --- Student Details ---
    ID     : 103
    Name   : Sita Thapa
    Marks  : 78.5, 85, 90, 72.5, 88
    Average: 82.8
    -----------------------
    

    Summary Table

    ConstructorParametersPurpose
    Student()NoneDefault values assigned
    Student(int, string)id, namePartial initialization
    Student(int, string, float[], int)id, name, marks array and countComplete initialization at the time of object creation

    Key Points Demonstrated

    FeatureWhere it appears in the program
    Constructor overloadingThree constructors share the name Student but differ in their parameter lists
    Compile time polymorphismThe compiler picks the constructor by matching the argument list, so the choice is made at compile time, not at run time
    Data hidingid, name and marks are private and are reached only through the member functions
    Member functionsreadDetails() takes input, displayDetails() prints the record and calculateAverage() returns the average
    Automatic invocationNo constructor is ever called by name; each runs the moment its object is created

    The three constructors are legal together because their signatures differ, Student(), Student(int, string) and Student(int, string, float[], int), and an overload set is resolved on the number and the type of the arguments only. Note that a return type may not be used to distinguish them, since a constructor has no return type at all.

    The average is computed as:

    $$\text{Average} = \frac{\sum_{i=1}^{n} marks_i}{n}$$

    so for the third object the average is (78.5 + 85 + 90 + 72.5 + 88) / 5, which is 82.8 as printed in the sample output.


    Conclusion

    The program defines a Student class with private data members and three overloaded constructors, then creates one object through each of them to show that the compiler selects the constructor from the argument list. Together with the member functions for reading, displaying and averaging the marks, it demonstrates encapsulation and compile time polymorphism in a single, exam-ready example.

  2. 210 marksMulti-level inheritanceAnswer

    Explain inheritance with suitable example.Differentiate between single, multiple, and hybrid inheritance.Write a program to show constructor invocation order in multilevel inheritance.[1+4+5]

    Inheritance is an Object-Oriented Programming (OOP) concept where a new class (called the derived class or child class) acquires the properties and behaviors (data members and member functions) of an existing class (called the base class...

  3. 310 marksOperator overloading definition and purposAnswer

    Explain operator overloading with example?Write a C++ class Number to store an integer. Overload addition (+) and comparison (==) operators, and show conversion between int and Number. Write a program to perform these operations.[2+8]

    Operator Overloading in C++

    (a) Explanation of Operator Overloading

    Operator overloading is a feature of C++ that allows existing operators (such as +, -, ==, <<, etc.) to be given additional meaning when applied to user-defined types (classes/objects). It enables objects of a class to be used with operators in a natural, intuitive way, just like built-in data types.

    Key Points:

    • The keyword operator followed by the operator symbol is used to define the overloaded function.
    • Syntax: return_type operator symbol (parameter list)
    • It does not change the precedence or associativity of operators.
    • At least one operand must be a user-defined type.

    (b) C++ Program

    #include <iostream>
    using namespace std;
    
    class Number {
    private:
        int value;
    
    public:
        // Default constructor
        Number() {
            value = 0;
        }
    
        // Parameterized constructor
        Number(int v) {
            value = v;
        }
    
        // -----------------------------------------------
        // Conversion: int to Number (done via constructor)
        // Conversion: Number to int (conversion operator)
        // -----------------------------------------------
        operator int() {
            return value;
        }
    
        // -----------------------------------------------
        // Overload addition operator (+)
        // Number + Number
        // -----------------------------------------------
        Number operator+(const Number& obj) {
            Number temp;
            temp.value = this->value + obj.value;
            return temp;
        }
    
        // -----------------------------------------------
        // Overload comparison operator (==)
        // -----------------------------------------------
        bool operator==(const Number& obj) {
            if (this->value == obj.value)
                return true;
            else
                return false;
        }
    
        // Display function
        void display() {
            cout << "Value = " << value << endl;
        }
    };
    
    // -----------------------------------------------
    // Main function to demonstrate operations
    // -----------------------------------------------
    int main() {
        // int to Number conversion (via constructor)
        int x = 10;
        Number n1 = x;          // implicit conversion: int -> Number
        Number n2(20);          // direct initialization
        Number n3 = 10;         // implicit conversion: int -> Number
    
        cout << "n1: "; n1.display();
        cout << "n2: "; n2.display();
        cout << "n3: "; n3.display();
    
        // Addition operator overloading
        Number n4 = n1 + n2;    // calls operator+
        cout << "\nAfter n4 = n1 + n2:" << endl;
        cout << "n4: "; n4.display();
    
        // Comparison operator overloading
        cout << "\nComparing n1 and n3 (both have value 10):" << endl;
        if (n1 == n3)
            cout << "n1 == n3: TRUE" << endl;
        else
            cout << "n1 == n3: FALSE" << endl;
    
        cout << "\nComparing n1 and n2:" << endl;
        if (n1 == n2)
            cout << "n1 == n2: TRUE" << endl;
        else
            cout << "n1 == n2: FALSE" << endl;
    
        // Number to int conversion (via conversion operator)
        int result = n4;        // implicit conversion: Number -> int
        cout << "\nNumber to int conversion (n4 -> int): " << result << endl;
    
        return 0;
    }
    

    Output

    n1: Value = 10
    n2: Value = 20
    n3: Value = 10
    
    After n4 = n1 + n2:
    n4: Value = 30
    
    Comparing n1 and n3 (both have value 10):
    n1 == n3: TRUE
    
    Comparing n1 and n2:
    n1 == n2: FALSE
    
    Number to int conversion (n4 -> int): 30
    

    Explanation of Key Concepts Used

    FeatureHow it is done
    int to NumberVia constructor Number(int v) - implicit conversion
    Number to intVia conversion operator operator int()
    + overloadingNumber operator+(const Number& obj)
    == overloadingbool operator==(const Number& obj)
    • Number n1 = x; calls the constructor Number(int v), converting int to Number.
    • int result = n4; calls operator int(), converting Number to int.
    • n1 + n2 calls operator+, returning a new Number object with the sum.
    • n1 == n3 calls operator==, returning true if values are equal.
  4. 45 marksDefault argumentsAnswer

    Explain default arguments and inline functions in C++ with suitable examples. [5]

    --- Definition: Default arguments are values provided in a function declaration that are automatically used when the caller does not supply a corresponding argument. They allow a function to be called with fewer arguments than it is defi...

  5. 55 marksThis pointer concept and usesAnswer

    What is the use of this pointer? Write a program to demonstrate it. [5]

    The this Pointer in C++

    Definition and Use

    The this pointer is an implicit pointer available inside every non-static member function of a class. It automatically points to the object that invoked the member function.

    Uses of this Pointer

    UseDescription
    Resolve name conflictDistinguish between member variables and parameters with the same name
    Return current objectReturn *this to enable method chaining
    Pass current objectPass the calling object to another function
    Self-reference checkCheck if two pointers point to the same object

    Program to Demonstrate this Pointer

    #include <iostream>
    using namespace std;
    
    class Student {
    private:
        int id;
        string name;
        float marks;
    
    public:
        // Use 1: Resolving name conflict between parameter and data member
        void setData(int id, string name, float marks) {
            this->id    = id;      // 'this->id' is member, 'id' is parameter
            this->name  = name;
            this->marks = marks;
        }
    
        // Use 2: Returning current object to enable method chaining
        Student& setId(int id) {
            this->id = id;
            return *this;          // returns reference to calling object
        }
    
        Student& setName(string name) {
            this->name = name;
            return *this;
        }
    
        Student& setMarks(float marks) {
            this->marks = marks;
            return *this;
        }
    
        void display() {
            cout << "ID    : " << this->id    << endl;
            cout << "Name  : " << this->name  << endl;
            cout << "Marks : " << this->marks << endl;
        }
    
        // Use 3: Compare if two objects are the same using this pointer
        bool isSame(Student &s) {
            if (this == &s) {
                return true;   // same object in memory
            }
            return false;
        }
    };
    
    int main() {
        // Demonstrating Use 1: Resolving name conflict
        cout << "--- Using setData (name conflict resolution) ---" << endl;
        Student s1;
        s1.setData(101, "Ram Sharma", 85.5);
        s1.display();
    
        // Demonstrating Use 2: Method chaining using *this
        cout << "\n--- Using Method Chaining ---" << endl;
        Student s2;
        s2.setId(102).setName("Sita Thapa").setMarks(90.0);
        s2.display();
    
        // Demonstrating Use 3: Self-reference check
        cout << "\n--- Self-reference Check ---" << endl;
        if (s1.isSame(s1)) {
            cout << "s1 and s1 are the SAME object." << endl;
        }
        if (!s1.isSame(s2)) {
            cout << "s1 and s2 are DIFFERENT objects." << endl;
        }
    
        return 0;
    }
    

    Output

    --- Using setData (name conflict resolution) ---
    ID    : 101
    Name  : Ram Sharma
    Marks : 85.5
    
    --- Using Method Chaining ---
    ID    : 102
    Name  : Sita Thapa
    Marks : 90
    
    --- Self-reference Check ---
    s1 and s1 are the SAME object.
    s1 and s2 are DIFFERENT objects.
    

    Key Points to Remember

    • this is a constant pointer (its address cannot be changed).
    • It holds the address of the calling object: this == &callingObject
    • It is not available in static member functions (static functions have no object context).
    • Dereferencing it (*this) gives the actual calling object.
  6. 65 marksFriend functionsAnswer

    Explain friend function and friend class with example. [5]

    Friend Function and Friend Class in C++

    Friend Function

    A friend function is a function that is not a member of a class but has access to the private and protected members of that class. It is declared inside the class using the keyword friend.

    Key Points:

    • It is defined outside the class scope
    • It is not called using an object (no this pointer)
    • It can access private data of the class directly

    Example of Friend Function

    #include <iostream>
    using namespace std;
    
    class Rectangle {
    private:
        float length, breadth;
    
    public:
        Rectangle(float l, float b) {
            length = l;
            breadth = b;
        }
    
        // Declaring friend function
        friend float calculateArea(Rectangle r);
    };
    
    // Definition of friend function (outside the class)
    float calculateArea(Rectangle r) {
        // Accessing private members directly
        return r.length * r.breadth;
    }
    
    int main() {
        Rectangle rect(5.0, 3.0);
        cout << "Area = " << calculateArea(rect) << endl;
        return 0;
    }
    

    Output:

    Area = 15
    

    Friend Class

    A friend class is a class that is granted access to the private and protected members of another class. When a class is declared as a friend, all member functions of that friend class can access private data of the other class.

    Key Points:

    • Declared using friend class ClassName; inside the class
    • Friendship is not mutual (if A is friend of B, B is not automatically friend of A)
    • Friendship is not inherited

    Example of Friend Class

    #include <iostream>
    using namespace std;
    
    class Engine {
    private:
        int horsepower;
    
    public:
        Engine(int hp) {
            horsepower = hp;
        }
    
        // Declaring Car as a friend class
        friend class Car;
    };
    
    class Car {
    public:
        void showEngineDetails(Engine e) {
            // Accessing private member of Engine class
            cout << "Engine Horsepower: " << e.horsepower << endl;
        }
    };
    
    int main() {
        Engine eng(150);
        Car car;
        car.showEngineDetails(eng);
        return 0;
    }
    

    Output:

    Engine Horsepower: 150
    

    Summary Table

    FeatureFriend FunctionFriend Class
    TypeA standalone functionA complete class
    Declarationfriend returnType funcName();friend class ClassName;
    AccessPrivate members of one classPrivate members of another class
    MembershipNot a member of the classNot a member of the class

    Note: Use of friend functions and classes should be minimized as they break the principle of data encapsulation in Object-Oriented Programming.

  7. 75 marksEarly binding versus late bindingAnswer

    Differentiate between early binding and late binding. Write a program to show dynamic polymorphism using virtual function. [2+3]

    --- Feature Early Binding (Static Binding) Late Binding (Dynamic Binding) --------- Time of Resolution Resolved at compile time Resolved at run time Mechanism Uses normal functions / function overloading Uses virtual functions Flexibilit...

  8. 85 marksFunction templatesAnswer

    What are function templates? Also, write a program that swaps two values using function templates. [1+4]

    Function Templates

    What are Function Templates?

    A function template is a blueprint or formula for creating a family of related functions. It allows a single function definition to work with different data types, where the actual data type is determined at compile time when the function is called.

    Key Points:

    • Defined using the keyword template followed by template parameter list
    • Enables generic programming in C++
    • The compiler automatically generates the appropriate function for each data type used
    • Avoids code duplication for functions that perform the same operation on different types

    Syntax:

    template <typename T>
    return_type function_name(T param1, T param2, ...) {
        // function body
    }
    

    Here, T is a type parameter (placeholder for an actual data type like int, float, char, etc.)


    Program: Swapping Two Values Using Function Templates

    #include <iostream>
    using namespace std;
    
    // Function template for swapping two values
    template <typename T>
    void swapValues(T &a, T &b) {
        T temp;
        temp = a;
        a = b;
        b = temp;
    }
    
    int main() {
        // Swapping two integers
        int x = 10, y = 20;
        cout << "Before swap (int): x = " << x << ", y = " << y << endl;
        swapValues(x, y);
        cout << "After swap  (int): x = " << x << ", y = " << y << endl;
    
        cout << endl;
    
        // Swapping two floats
        float p = 3.14, q = 7.77;
        cout << "Before swap (float): p = " << p << ", q = " << q << endl;
        swapValues(p, q);
        cout << "After swap  (float): p = " << p << ", q = " << q << endl;
    
        cout << endl;
    
        // Swapping two characters
        char c1 = 'A', c2 = 'Z';
        cout << "Before swap (char): c1 = " << c1 << ", c2 = " << c2 << endl;
        swapValues(c1, c2);
        cout << "After swap  (char): c1 = " << c1 << ", c2 = " << c2 << endl;
    
        return 0;
    }
    

    Output

    Before swap (int): x = 10, y = 20
    After swap  (int): x = 20, y = 10
    
    Before swap (float): p = 3.14, q = 7.77
    After swap  (float): p = 7.77, q = 3.14
    
    Before swap (char): c1 = A, c2 = Z
    After swap  (char): c1 = Z, c2 = A
    

    Explanation

    AspectDetail
    template <typename T>Declares T as a generic type parameter
    T &a, T &bPass by reference so original values are modified
    T tempTemporary variable of the same generic type
    Compiler behaviorGenerates separate swapValues<int>, swapValues<float>, swapValues<char> automatically

    Advantage: Without templates, we would need to write three separate swap functions for int, float, and char. The function template handles all types with a single definition.

  9. 95 marksVirtual base class and ambiguity resolutioAnswer

    Explain ambiguity problem in multiple inheritance with example. How is it resolved using virtual base class? [5]

    When a class inherits from two or more base classes that themselves share a common base class, the derived class ends up with multiple copies of the common base class members. This creates ambiguity because the compiler cannot determine ...

  10. 105 marksException handling definition and purposeAnswer

    Write a program to handle division by zero exception using try, catch, and throw. [5]

    Handling Division by Zero Exception Using try, catch, and throw

    Concept

    In C++, exception handling uses three keywords:

    • try - block of code that may throw an exception
    • throw - used to throw/raise an exception when an error occurs
    • catch - block that handles the thrown exception

    Program

    #include <iostream>
    using namespace std;
    
    // Function to perform division
    double divide(int numerator, int denominator) {
        if (denominator == 0) {
            throw "Division by zero is not allowed!";  // throw exception
        }
        return (double)numerator / denominator;
    }
    
    int main() {
        int a, b;
    
        cout << "Enter numerator: ";
        cin >> a;
    
        cout << "Enter denominator: ";
        cin >> b;
    
        try {
            // Code that may cause exception
            double result = divide(a, b);
            cout << "Result: " << a << " / " << b << " = " << result << endl;
        }
        catch (const char* msg) {
            // Handle the exception
            cout << "Exception caught: " << msg << endl;
        }
    
        cout << "Program continues after exception handling." << endl;
    
        return 0;
    }
    

    Sample Output

    Case 1: Normal Division

    Enter numerator: 10
    Enter denominator: 2
    Result: 10 / 2 = 5
    Program continues after exception handling.
    

    Case 2: Division by Zero

    Enter numerator: 10
    Enter denominator: 0
    Exception caught: Division by zero is not allowed!
    Program continues after exception handling.
    

    Explanation

    KeywordRole in Program
    throwThrows a string message when denominator is 0
    tryWraps the call to divide() that may fail
    catchCatches the thrown string and displays the error
    • When denominator is not zero, the division executes normally.
    • When denominator is zero, throw transfers control directly to the catch block, skipping the remaining try block.
    • After the catch block executes, the program continues normally, demonstrating graceful error handling.
  11. 115 marksText file reading and writingAnswer

    Write a C++ program to read a text file named data.txt and display its contents on the screen. Also, count the number of lines, words, and characters in the file and display these counts after showing the file content. [5]

    Suppose data.txt contains: Program Output: Concept Description ------ ifstream Used to open and read from a file getline() Reads one complete line at a time inFile check Verifies file was opened successfully line.length() Returns number ...

  12. 125 marksAbstract classes and concrete classesAnswer

    What is the difference between abstract class and concrete class? Explain with example. [5]

    Abstract Class and Concrete Class in C++

    What makes a class abstract in C++

    C++ has no abstract keyword. A class becomes abstract the moment it declares at least one pure virtual function, written by putting = 0 after a virtual member function instead of a body:

    virtual double area() const = 0;   // pure virtual, so the class is abstract
    

    An abstract class cannot be instantiated. The compiler refuses Shape s; with "cannot declare variable of abstract type". It can still be used as a base type: pointers and references of the abstract type are perfectly legal, and they are exactly how runtime polymorphism is obtained.

    Because objects are usually deleted through a base pointer, an abstract base class should also declare a virtual destructor, otherwise the derived part of the object is never destroyed.

    Key characteristics:

    • At least one member function is declared pure virtual with = 0.
    • No object of the class can be created, though base pointers and references are allowed.
    • It may also contain ordinary data members and fully implemented member functions.
    • A derived class stays abstract until it overrides every pure virtual it inherits.

    What a concrete class is

    A concrete class supplies a body for every function it declares or inherits, so nothing is left unimplemented. It can be instantiated directly, and it is the only kind of class from which real objects are made. A concrete class is very often a class derived from an abstract base that has filled in the missing implementations.

    Key characteristics:

    • Every inherited pure virtual function has been overridden.
    • Objects can be created on the stack, with new, or inside a container.
    • It may be a standalone class or the leaf of an inheritance hierarchy.

    Comparison

    FeatureAbstract classConcrete class
    InstantiationNot possible, only pointers and referencesObjects can be created directly
    FunctionsHas at least one pure virtual (= 0)Every function has a body
    How it is declaredNo keyword, the = 0 on a virtual marks itNothing special is written
    PurposeDefines an interface or a common templateProvides a usable, complete type
    DestructorShould be declared virtualVirtual only if it is itself a base

    In Java the same idea is written with the abstract keyword on the class and on the method; in C++ the = 0 on a virtual function carries that meaning by itself.

    Worked example

    #include <iostream>
    #include <string>
    
    // Abstract class: it declares a pure virtual function, so no Shape object can exist.
    class Shape {
    protected:
        std::string color;
    public:
        explicit Shape(const std::string& c) : color(c) {}
        virtual ~Shape() = default;        // virtual destructor for safe deletion via a base pointer
    
        virtual double area() const = 0;   // pure virtual: this is what makes Shape abstract
    
        void displayColor() const {        // an ordinary member, already implemented
            std::cout << "Color: " << color << "\n";
        }
    };
    
    // Concrete class: it gives a body to the inherited pure virtual function.
    class Circle : public Shape {
        double radius;
    public:
        Circle(double r, const std::string& c) : Shape(c), radius(r) {}
        double area() const override { return 3.14159 * radius * radius; }
    };
    
    // Another concrete class from the same abstract base.
    class Rectangle : public Shape {
        double length, width;
    public:
        Rectangle(double l, double w, const std::string& c)
            : Shape(c), length(l), width(w) {}
        double area() const override { return length * width; }
    };
    
    int main() {
        // Shape s("Red");   // compile error: cannot declare variable of abstract type Shape
    
        Circle c(5.0, "Red");
        c.displayColor();
        std::cout << "Circle area: " << c.area() << "\n";
    
        Rectangle r(4.0, 6.0, "Blue");
        r.displayColor();
        std::cout << "Rectangle area: " << r.area() << "\n";
    
        const Shape& s = c;    // a reference to the abstract type is legal and dispatches virtually
        std::cout << "Through base reference: " << s.area() << "\n";
        return 0;
    }
    

    Output:

    Color: Red
    Circle area: 78.5398
    Color: Blue
    Rectangle area: 24
    Through base reference: 78.5398
    

    Here Shape is the abstract class. It fixes the interface every shape must offer, area(), without deciding how any particular shape computes it, and it supplies one ready made service, displayColor(). Circle and Rectangle are the concrete classes: each overrides area(), so each can be instantiated. The commented out line shows the practical difference, since only the concrete types produce objects while the abstract type produces the common contract they all obey.