Chapter 13 Intermediate 60 Questions

Practice Questions — OOP - Classes, Objects, and Constructors

← Back to Notes
7 Easy
7 Medium
6 Hard

Topic-Specific Questions

Question 1
Easy
What is the output?
class Greet {
public:
    Greet() { cout << "Hello "; }
    ~Greet() { cout << "Bye "; }
};

int main() {
    Greet g;
    cout << "World ";
}
The constructor runs when g is created. The destructor runs when main ends.
Hello World Bye
Question 2
Easy
What is the output?
class Box {
public:
    int value;
    Box() : value(0) {}
    Box(int v) : value(v) {}
};

Box a;
Box b(10);
cout << a.value << " " << b.value;
Box a calls the default constructor. Box b(10) calls the parameterized constructor.
0 10
Question 3
Easy
What is the output?
class Counter {
public:
    static int count;
    Counter() { count++; }
};
int Counter::count = 0;

Counter a, b, c;
cout << Counter::count;
Static members are shared. Each constructor increments the same count.
3
Question 4
Easy
What is the output?
class Point {
public:
    int x, y;
    Point(int x, int y) {
        this->x = x;
        this->y = y;
    }
};

Point p(3, 7);
cout << p.x << " " << p.y;
this->x refers to the member; x refers to the parameter.
3 7
Question 5
Medium
What is the output?
class A {
public:
    A() { cout << "A "; }
    ~A() { cout << "~A "; }
};

int main() {
    A a1;
    A a2;
    A a3;
    cout << "| ";
}
Destructors run in reverse order of construction.
A A A | ~A ~A ~A
Question 6
Medium
What is the output?
class Tag {
    string name;
public:
    Tag(string n) : name(n) { cout << "+" << name << " "; }
    Tag(const Tag& t) : name(t.name + "_c") { cout << "C:" << name << " "; }
    ~Tag() { cout << "-" << name << " "; }
};

Tag t1("X");
Tag t2 = t1;

(Assume this is inside main)

Tag t2 = t1 invokes the copy constructor. Destructors run in reverse.
+X C:X_c
(After main: -X_c -X )
Question 7
Medium
What is the output?
class Chain {
    int val;
public:
    Chain(int v) : val(v) {}
    Chain& add(int n) {
        val += n;
        return *this;
    }
    void print() const {
        cout << val;
    }
};

Chain c(10);
c.add(5).add(3).add(2).print();
Each add() returns *this, allowing the next call on the same object.
20
Question 8
Medium
What is the output?
class Item {
    static int created;
    static int alive;
public:
    Item() { created++; alive++; }
    ~Item() { alive--; }
    static void stats() {
        cout << "Created: " << created << ", Alive: " << alive << endl;
    }
};
int Item::created = 0;
int Item::alive = 0;

int main() {
    Item a, b;
    Item::stats();
    {
        Item c;
        Item::stats();
    }
    Item::stats();
}
c is destroyed when the inner block ends. created never decreases.
Created: 2, Alive: 2
Created: 3, Alive: 3
Created: 3, Alive: 2
Question 9
Hard
What is the output?
class A {
public:
    A() { cout << "A() "; }
    A(int x) { cout << "A(" << x << ") "; }
    A(const A& a) { cout << "A(copy) "; }
    ~A() { cout << "~A "; }
};

A func() {
    A local(5);
    return local;
}

int main() {
    A obj = func();
    cout << "| ";
}
The copy constructor may or may not be called due to copy elision (NRVO). Without elision: local is constructed, copied, destroyed. With elision: only one construction.
Without copy elision: A(5) A(copy) ~A | ~A
With copy elision (common): A(5) | ~A
Question 10
Hard
What is the output?
class Nested {
public:
    Nested() { cout << "N "; }
    ~Nested() { cout << "~N "; }
};

class Outer {
    Nested n1;
    Nested n2;
public:
    Outer() { cout << "O "; }
    ~Outer() { cout << "~O "; }
};

Outer obj;
Member objects are constructed before the class constructor body. Destruction is in reverse.
N N O
(After main: ~O ~N ~N )
Question 11
Hard
What is the output?
class Val {
    int x;
public:
    Val(int v = 0) : x(v) { cout << "C:" << x << " "; }
    ~Val() { cout << "D:" << x << " "; }
};

Val arr[3] = {Val(10), Val(20)};

(Assume inside main)

The third element uses the default argument value. Destructors run in reverse.
C:10 C:20 C:0
(After main: D:0 D:20 D:10 )

Mixed & Application Questions

Question 1
Easy
What is the difference between a class and a struct in C++?
Think about the default access specifier.
In C++, the only difference is the default access specifier: class members are private by default, while struct members are public by default. In every other respect (constructors, destructors, inheritance, virtual functions), they are identical.
Question 2
Easy
What is the output?
struct Point {
    int x, y;
};

Point p;
p.x = 5;
p.y = 10;
cout << p.x + p.y;
struct members are public by default.
15
Question 3
Easy
What is the output?
class Num {
public:
    int val;
    Num(int v) : val(v) {}
};

Num a(5), b(3);
cout << a.val * b.val;
Two objects with their own val members.
15
Question 4
Medium
What is the output?
class Scope {
public:
    string name;
    Scope(string n) : name(n) { cout << "+" << name << " "; }
    ~Scope() { cout << "-" << name << " "; }
};

int main() {
    Scope a("A");
    {
        Scope b("B");
        Scope c("C");
    }
    Scope d("D");
}
B and C are destroyed at the end of the inner block. A and D are destroyed at the end of main.
+A +B +C -C -B +D -D -A
Question 5
Medium
Why should you use initializer lists instead of assignment in constructor bodies?
Think about const members, reference members, and efficiency.
Initializer lists directly initialize members, while assignment in the body first default-constructs and then assigns. Initializer lists are: (1) Required for const members, reference members, and base class constructors. (2) More efficient for class-type members (avoids unnecessary default construction + assignment). (3) Members are initialized in declaration order regardless of the list order.
Question 6
Medium
What is the output?
class Demo {
    int x;
public:
    Demo(int val) : x(val) {}
    void show() const {
        cout << x << " ";
    }
};

const Demo d(42);
d.show();
// d.x = 10;  // Would this work?
d is const, so only const member functions can be called, and no members can be modified.
42
(d.x = 10 would fail because x is private AND d is const)
Question 7
Hard
What is the output?
class A {
public:
    int x;
    A() : x(0) {}
    A(int v) : x(v) {}
    A(const A& other) : x(other.x) {
        cout << "copy(" << x << ") ";
    }
};

void func(A obj) {
    cout << obj.x << " ";
}

A a(10);
func(a);
Passing by value triggers the copy constructor.
copy(10) 10
Question 8
Hard
What is sizeof the following class?
class Mystery {
    double d;    // 8 bytes
    char c;      // 1 byte
    int i;       // 4 bytes
};
cout << sizeof(Mystery);
Think about alignment. double requires 8-byte alignment.
16
Question 9
Hard
What is the output?
class Singleton {
    static Singleton* instance;
    int value;
    Singleton(int v) : value(v) {}
public:
    static Singleton* get(int v) {
        if (!instance)
            instance = new Singleton(v);
        return instance;
    }
    int getValue() const { return value; }
};
Singleton* Singleton::instance = nullptr;

cout << Singleton::get(42)->getValue() << endl;
cout << Singleton::get(99)->getValue() << endl;
The first call creates the instance. The second call returns the existing one.
42
42

Multiple Choice Questions

MCQ 1
What is the default access specifier for members of a class in C++?
  • A. public
  • B. private
  • C. protected
  • D. internal
Answer: B
B is correct. In a class, members are private by default. In a struct, members are public by default. internal (D) is not a C++ access specifier.
MCQ 2
What is a constructor in C++?
  • A. A function that returns an object
  • B. A special member function called automatically when an object is created
  • C. A function that destroys an object
  • D. A function that copies an object
Answer: B
B is correct. A constructor has the same name as the class, no return type, and is called automatically when an object is created. C describes a destructor, D describes a copy operation.
MCQ 3
What is the correct syntax for a destructor of class MyClass?
  • A. void ~MyClass()
  • B. ~MyClass()
  • C. delete MyClass()
  • D. MyClass::destroy()
Answer: B
B is correct. A destructor is named ~ClassName() with no return type and no parameters. It cannot return void (A is wrong), is not the delete operator (C), and has a specific syntax (not a regular named method like D).
MCQ 4
What does the this pointer hold in a member function?
  • A. The address of the class definition
  • B. The address of the current object
  • C. The address of the first member variable
  • D. nullptr by default
Answer: B
B is correct. this is a pointer to the object on which the member function is being called. It allows the function to refer to the invoking object.
MCQ 5
In what order are destructors called for local objects?
  • A. Same order as construction
  • B. Reverse order of construction
  • C. Alphabetical order
  • D. Random order
Answer: B
B is correct. C++ guarantees that destructors of local objects are called in the reverse order of their construction. This is LIFO (last in, first out) behavior.
MCQ 6
Which of the following REQUIRES an initializer list?
  • A. Initializing an int member
  • B. Initializing a const member
  • C. Initializing a public member
  • D. Initializing a static member
Answer: B
B is correct. A const member must be initialized (not assigned) at construction time, which requires an initializer list. The same applies to reference members and base class constructors. Static members (D) are defined outside the class.
MCQ 7
What can a static member function access?
  • A. Both static and non-static members
  • B. Only non-static members
  • C. Only static members
  • D. Nothing -- static functions are empty
Answer: C
C is correct. A static member function does not have a this pointer, so it cannot access non-static members (which require an object). It can only access static members of the class.
MCQ 8
What is the sizeof an empty class in C++?
  • A. 0
  • B. 1
  • C. 4
  • D. Depends on the compiler
Answer: B
B is correct. An empty class has sizeof 1 (not 0). This ensures that every object has a unique address. If it were 0, two objects of the same empty class could have the same address, violating the identity principle.
MCQ 9
When is the copy constructor called?
  • A. Only when using = in a declaration
  • B. When passing an object by value, returning by value, or using = in a declaration
  • C. Only when explicitly called with ClassName(obj)
  • D. When assigning one object to another after both are initialized
Answer: B
B is correct. The copy constructor is called in three scenarios: (1) T obj2 = obj1; in a declaration, (2) passing an object by value to a function, (3) returning an object by value (unless elided). D describes the copy assignment operator (operator=), not the copy constructor.
MCQ 10
What is the "most vexing parse" in C++?
  • A. A syntax error when overloading operators
  • B. A declaration that looks like an object creation but is parsed as a function declaration
  • C. An error caused by missing semicolons
  • D. A conflict between class and struct keywords
Answer: B
B is correct. Widget w(); looks like creating a Widget with the default constructor, but C++ parses it as a function declaration (a function named w that returns Widget). Use Widget w; or Widget w{}; instead.
MCQ 11
In which order are member objects constructed and destroyed?
  • A. Constructed and destroyed in declaration order
  • B. Constructed in declaration order, destroyed in reverse order
  • C. Constructed in initializer list order, destroyed in reverse
  • D. Random order determined by the compiler
Answer: B
B is correct. Member objects are always constructed in the order they are declared in the class (not the initializer list order), and destroyed in reverse. This is guaranteed by the C++ standard.
MCQ 12
What happens if a class has a pointer member and uses the compiler-generated copy constructor?
  • A. The pointer member is set to nullptr
  • B. A deep copy of the pointed-to data is made
  • C. A shallow copy is made (both objects point to the same memory)
  • D. Compilation error
Answer: C
C is correct. The compiler-generated copy constructor performs a memberwise (shallow) copy. For pointer members, this means both the original and the copy point to the same address. This leads to double-free bugs if the destructor frees the memory.
MCQ 13
Which keyword prevents a member from being modified in a const member function?
  • A. volatile
  • B. mutable reverses this restriction
  • C. static
  • D. const after the parameter list
Answer: D
D is correct. Placing const after the parameter list (int getValue() const) makes the function a const member function that cannot modify any member. mutable (B) is the keyword that allows a member to be modified even in a const function, but the question asks what prevents modification.

Coding Challenges

Challenge 1: Student Class with Constructors

Easy
Create a Student class with name (string) and marks (double). Write a default constructor (name="Unknown", marks=0), a parameterized constructor, and a display() method. Create 3 students and display them.
Sample Input
(No input required)
Sample Output
Unknown - 0 Rahul - 85.5 Priya - 92.3
Use initializer lists. Mark display() as const.
#include <iostream>
#include <string>
using namespace std;

class Student {
    string name;
    double marks;
public:
    Student() : name("Unknown"), marks(0) {}
    Student(string n, double m) : name(n), marks(m) {}
    void display() const {
        cout << name << " - " << marks << endl;
    }
};

int main() {
    Student s1;
    Student s2("Rahul", 85.5);
    Student s3("Priya", 92.3);
    s1.display();
    s2.display();
    s3.display();
    return 0;
}

Challenge 2: Counter with Static Members

Easy
Create a Counter class with a static member totalCount that tracks how many Counter objects currently exist. The constructor increments it, the destructor decrements it. Add a static function getCount(). Demonstrate by creating and destroying objects in different scopes.
Sample Input
(No input required)
Sample Output
Count: 2 Count: 3 Count: 2 Count: 0
Use static member variable and static function. Define static member outside the class.
#include <iostream>
using namespace std;

class Counter {
    static int totalCount;
public:
    Counter() { totalCount++; }
    ~Counter() { totalCount--; }
    static int getCount() { return totalCount; }
};
int Counter::totalCount = 0;

int main() {
    Counter a, b;
    cout << "Count: " << Counter::getCount() << endl;  // 2
    {
        Counter c;
        cout << "Count: " << Counter::getCount() << endl;  // 3
    }
    cout << "Count: " << Counter::getCount() << endl;  // 2
    return 0;
    // After main, a and b are destroyed
}
// Final count would be 0

Challenge 3: BankAccount with Encapsulation

Medium
Create a BankAccount class with private members: accountHolder (string), balance (double). Provide a parameterized constructor, deposit(double), withdraw(double) with validation (no negative amounts, no overdraft), and display() const. Track total accounts created using a static member.
Sample Input
(No input required)
Sample Output
Arjun: Rs.10000 Deposited Rs.5000. New balance: Rs.15000 Withdrew Rs.3000. New balance: Rs.12000 Insufficient balance! Total accounts: 2
All data members must be private. Validate inputs. Use initializer list.
#include <iostream>
#include <string>
using namespace std;

class BankAccount {
    string holder;
    double balance;
    static int totalAccounts;
public:
    BankAccount(string h, double b) : holder(h), balance(b) {
        totalAccounts++;
    }
    void deposit(double amount) {
        if (amount <= 0) { cout << "Invalid amount!" << endl; return; }
        balance += amount;
        cout << "Deposited Rs." << amount << ". New balance: Rs." << balance << endl;
    }
    void withdraw(double amount) {
        if (amount <= 0) { cout << "Invalid amount!" << endl; return; }
        if (amount > balance) { cout << "Insufficient balance!" << endl; return; }
        balance -= amount;
        cout << "Withdrew Rs." << amount << ". New balance: Rs." << balance << endl;
    }
    void display() const {
        cout << holder << ": Rs." << balance << endl;
    }
    static int getTotalAccounts() { return totalAccounts; }
};
int BankAccount::totalAccounts = 0;

int main() {
    BankAccount acc1("Arjun", 10000);
    BankAccount acc2("Meera", 5000);
    acc1.display();
    acc1.deposit(5000);
    acc1.withdraw(3000);
    acc1.withdraw(20000);
    cout << "Total accounts: " << BankAccount::getTotalAccounts() << endl;
    return 0;
}

Challenge 4: Deep Copy Constructor for Dynamic Array Class

Medium
Create an IntArray class that wraps a dynamic int array. Implement: constructor(int size), deep copy constructor, destructor, set(int index, int value), get(int index), and display(). Demonstrate that modifying the copy does not affect the original.
Sample Input
(No input required)
Sample Output
Original: 10 20 30 Copy: 10 20 30 After modifying copy: Original: 10 20 30 Copy: 10 99 30
Implement a deep copy constructor. The destructor must free memory. Demonstrate independence of original and copy.
#include <iostream>
using namespace std;

class IntArray {
    int* data;
    int size;
public:
    IntArray(int n) : size(n), data(new int[n]()) {}
    IntArray(const IntArray& other) : size(other.size), data(new int[other.size]) {
        for (int i = 0; i < size; i++) data[i] = other.data[i];
    }
    ~IntArray() { delete[] data; }
    void set(int i, int val) { data[i] = val; }
    int get(int i) const { return data[i]; }
    void display() const {
        for (int i = 0; i < size; i++) cout << data[i] << " ";
        cout << endl;
    }
};

int main() {
    IntArray original(3);
    original.set(0, 10);
    original.set(1, 20);
    original.set(2, 30);
    cout << "Original: ";
    original.display();

    IntArray copy = original;  // deep copy
    cout << "Copy: ";
    copy.display();

    copy.set(1, 99);
    cout << "After modifying copy:" << endl;
    cout << "Original: ";
    original.display();
    cout << "Copy: ";
    copy.display();
    return 0;
}

Challenge 5: Method Chaining -- QueryBuilder

Hard
Create a QueryBuilder class that builds a SQL-like query string using method chaining. Methods: select(string columns), from(string table), where(string condition), orderBy(string column), build() which returns the final query string. Each method returns *this.
Sample Input
(No input required)
Sample Output
SELECT name, marks FROM students WHERE marks > 80 ORDER BY marks
Use the this pointer and return *this from each method. Use const for build().
#include <iostream>
#include <string>
using namespace std;

class QueryBuilder {
    string query;
public:
    QueryBuilder& select(const string& cols) {
        query = "SELECT " + cols;
        return *this;
    }
    QueryBuilder& from(const string& table) {
        query += " FROM " + table;
        return *this;
    }
    QueryBuilder& where(const string& condition) {
        query += " WHERE " + condition;
        return *this;
    }
    QueryBuilder& orderBy(const string& col) {
        query += " ORDER BY " + col;
        return *this;
    }
    string build() const { return query; }
};

int main() {
    QueryBuilder qb;
    string query = qb.select("name, marks")
                     .from("students")
                     .where("marks > 80")
                     .orderBy("marks")
                     .build();
    cout << query << endl;
    return 0;
}

Challenge 6: Matrix Class with Operator Overloading Preview

Hard
Create a Matrix class for 2x2 matrices. Implement: constructor(4 values), copy constructor, display(), add(const Matrix&) that returns a new Matrix with the sum, and a static identity() that returns the 2x2 identity matrix. Demonstrate all operations.
Sample Input
(No input required)
Sample Output
Matrix A: 1 2 3 4 Matrix B: 5 6 7 8 A + B: 6 8 10 12 Identity: 1 0 0 1
Use initializer list. Pass by const reference. Use const member functions where appropriate.
#include <iostream>
using namespace std;

class Matrix {
    int data[2][2];
public:
    Matrix(int a, int b, int c, int d) {
        data[0][0] = a; data[0][1] = b;
        data[1][0] = c; data[1][1] = d;
    }
    Matrix(const Matrix& other) {
        for (int i = 0; i < 2; i++)
            for (int j = 0; j < 2; j++)
                data[i][j] = other.data[i][j];
    }
    Matrix add(const Matrix& other) const {
        return Matrix(
            data[0][0] + other.data[0][0],
            data[0][1] + other.data[0][1],
            data[1][0] + other.data[1][0],
            data[1][1] + other.data[1][1]
        );
    }
    static Matrix identity() {
        return Matrix(1, 0, 0, 1);
    }
    void display() const {
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 2; j++)
                cout << data[i][j] << " ";
            cout << endl;
        }
    }
};

int main() {
    Matrix a(1, 2, 3, 4);
    Matrix b(5, 6, 7, 8);
    cout << "Matrix A:" << endl;
    a.display();
    cout << "Matrix B:" << endl;
    b.display();
    Matrix c = a.add(b);
    cout << "A + B:" << endl;
    c.display();
    cout << "Identity:" << endl;
    Matrix::identity().display();
    return 0;
}

Need to Review the Concepts?

Go back to the detailed notes for this chapter.

Read Chapter Notes

Want to learn C++ with a live mentor?

Explore our C++ Masterclass