Practice Questions — OOP - Classes, Objects, and Constructors
← Back to NotesTopic-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 10Question 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.
3Question 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 7Question 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.
20Question 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: 2Created: 3, Alive: 3Created: 3, Alive: 2Question 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:
With copy elision (common):
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.
15Question 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.
15Question 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.
16Question 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.
4242Multiple Choice Questions
MCQ 1
What is the default access specifier for members of a class in C++?
Answer: B
B is correct. In a
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++?
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.
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?
Answer: B
B is correct. A destructor is named
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?
Answer: B
B is correct.
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?
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.
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?
Answer: B
B is correct. A
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?
Answer: C
C is correct. A static member function does not have a
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++?
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.
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?
Answer: B
B is correct. The copy constructor is called in three scenarios: (1)
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++?
Answer: B
B is correct.
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?
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.
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?
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.
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?
Answer: D
D is correct. Placing
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
EasyCreate 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
EasyCreate 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 0Challenge 3: BankAccount with Encapsulation
MediumCreate 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
MediumCreate 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
HardCreate 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
HardCreate 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 NotesWant to learn C++ with a live mentor?
Explore our C++ Masterclass