16. What does this static-member program print?
#include <iostream>
class Counter {
public:
static int count;
Counter() { count++; }
};
int Counter::count = 0;
int main() {
Counter a;
Counter b;
Counter c;
std::cout << Counter::count << "\n";
return 0;
}
Output:
3
A static member is shared by all instances — it is not per-object. Each of the three Counter constructions increments the same count, so it ends at 3. It must be defined (and optionally initialized) outside the class, as int Counter::count = 0; does here.
17. What happens when you call a non-const method on a const object?
#include <iostream>
class Point {
int x;
public:
Point(int v) : x(v) {}
int get() const { return x; }
int get2() { return x; }
};
int main() {
const Point p(7);
std::cout << p.get() << "\n";
std::cout << p.get2() << "\n";
return 0;
}
Output:
Compile error: cannot call non-const member function get2() on a const object.
p.get() is a const member function, so calling it on a const object is fine. But p.get2() is non-const — a const object can only call const member functions, so the program fails to compile. This is exactly why const-correctness matters: marking methods const when they don’t modify state lets them be used on const objects.
18. What does this move-vs-copy print?
#include <iostream>
#include <utility>
struct Box {
int *p;
Box(int v) : p(new int(v)) {}
Box(const Box &o) : p(new int(*o.p)) {
std::cout << "copy ";
}
Box(Box &&o) noexcept : p(o.p) {
o.p = nullptr;
std::cout << "move ";
}
~Box() { delete p; }
};
int main() {
Box a(1);
Box b = a;
Box c = std::move(a);
std::cout << "\n";
return 0;
}
Output:
copy move
Box b = a takes an lvalue, so it uses the copy constructor (deep copy) → prints copy. Box c = std::move(a) takes an rvalue, so it uses the move constructor (steals the pointer) → prints move. The output is copy move. Move transfers resources; copy duplicates them.
19. What happens when you use a finally block in C++?
#include <iostream>
#include <stdexcept>
int main() {
try {
std::cout << "try ";
throw std::runtime_error("boom");
} catch (const std::exception &e) {
std::cout << "caught ";
} finally {
std::cout << "finally ";
}
std::cout << "\n";
return 0;
}
Output:
Compile error: C++ has no finally keyword.
There is no finally block in C++ — finally is not a keyword, so this program does not compile. The C++ idiom is RAII: destructors of local objects run automatically during stack unwinding, which is what Java/Python programmers use finally for. This “C++ has no finally” fact is one of the most-tested C++ vs Java/Python differences.
20. What does this exception catch-order print?
#include <iostream>
#include <stdexcept>
int main() {
try {
throw std::runtime_error("boom");
} catch (const std::runtime_error &e) {
std::cout << "runtime\n";
} catch (const std::exception &e) {
std::cout << "exception\n";
}
return 0;
}
Output:
runtime
std::runtime_error derives from std::exception. Exception handlers are matched in order and the first matching type wins. The more specific catch (const std::runtime_error &) comes first and matches, printing "runtime". If the order were reversed, the base-class handler would catch everything — that’s why you always put derived types first.
21. What does this new/delete print?
#include <iostream>
int main() {
int *p = new int(42);
std::cout << *p << "\n";
delete p;
return 0;
}
Output:
42
new int(42) allocates memory on the heap and initializes it to 42. *p dereferences to read the value, printing 42. delete p frees the memory. (Reading a pointer after delete would be undefined behavior — one reason modern C++ prefers smart pointers.)
22. What does this vector-of-strings print?
#include <iostream>
#include <string>
#include <vector>
int main() {
std::vector<std::string> v = {"a", "b", "c"};
std::cout << v.size() << "\n";
std::cout << v[1] << "\n";
std::cout << v.front() << " " << v.back() << "\n";
return 0;
}
Output:
3
b
a c
v.size() is the element count (3), v[1] is the second element ("b"), v.front() is "a" and v.back() is "c". Basic std::vector accessors are a common entry-level question.
23. What does this range-for print?
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {10, 20, 30};
for (int x : v)
std::cout << x << " ";
for (int &x : v)
x += 1;
std::cout << "\n";
for (int x : v)
std::cout << x << " ";
std::cout << "\n";
return 0;
}
Output:
10 20 30
11 21 31
The first range-for copies each element (int x), printing 10 20 30. The second uses a reference (int &x), so x += 1 modifies the actual vector elements, making them 11 21 31. Copy vs reference in range-for is a frequent C++11+ interview point.
24. What does this map-lookup print?
#include <iostream>
#include <map>
int main() {
std::map<std::string, int> m;
m["a"] = 1;
m["b"] = 2;
std::cout << m.size() << "\n";
std::cout << m["a"] << " ";
m["c"];
std::cout << m.size() << "\n";
return 0;
}
Output:
2
1 3
m["a"] reads the value 1. But m["c"] with operator[] inserts a default-constructed value (0) for a missing key — so m.size() becomes 3. operator[] inserts; m.at("c") would throw instead. The insert-on-access behavior of map::operator[] is a classic trap.
25. What does this iterator print?
#include <iostream>
#include <vector>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
std::cout << *v.begin() << "\n";
std::cout << *(v.end() - 1) << "\n";
std::cout << (v.end() - v.begin()) << "\n";
return 0;
}
Output:
1
5
5
v.begin() points to the first element → 1. v.end() - 1 points to the last element → 5 (end is one past the last). v.end() - v.begin() is the distance — the number of elements, 5. The half-open [begin, end) range is the foundation of all STL iteration.
26. What does this lambda capture print?
#include <iostream>
int main() {
int x = 10;
auto byValue = [x]() { std::cout << x << " "; };
auto byRef = [&x]() { std::cout << x << "\n"; };
x = 20;
byValue();
byRef();
return 0;
}
Output:
10 20
[x] captures a copy of x at the time the lambda is created, so by the time it’s called, byValue still prints the captured 10. [&x] captures by reference, so it sees the current value 20. Copy vs reference capture is a staple modern C++ question.
27. What does this smart-pointer print?
#include <iostream>
#include <memory>
struct Node {
int v;
Node(int x) : v(x) {}
};
int main() {
std::shared_ptr<Node> p = std::make_shared<Node>(5);
std::cout << p->v << "\n";
std::cout << p.use_count() << " ";
std::shared_ptr<Node> q = p;
std::cout << q.use_count() << "\n";
return 0;
}
Output:
5
1 2
p->v is 5. p.use_count() is 1 right after creation (only p owns it). Then q = p shares ownership, so q.use_count() is 2 — but p.use_count() was already printed before q was created. shared_ptr ref-counts; when the last owner dies the object is destroyed automatically. Ownership and use_count is the standard smart-pointer interview question.
28. What does this virtual-in-constructor print?
#include <iostream>
class Base {
public:
Base() { std::cout << "Base ctor, show: "; show(); }
virtual void show() { std::cout << "Base\n"; }
};
class Derived : public Base {
public:
Derived() { std::cout << "Derived ctor, show: "; show(); }
void show() override { std::cout << "Derived\n"; }
};
int main() {
Derived d;
return 0;
}
Output:
Base ctor, show: Base
Derived ctor, show: Derived
During the Base constructor, virtual dispatch resolves to Base::show — the Derived part doesn’t exist yet. Only after the Derived constructor begins does dispatch reach Derived::show. So we get Base first, then Derived. Calling virtual functions from constructors is a common C++ interview trap.
29. What does this operator-overload print?
#include <iostream>
class Num {
int v;
public:
Num(int x) : v(x) {}
Num operator+(const Num &o) const { return Num(v + o.v); }
int get() const { return v; }
};
int main() {
Num a(10), b(20);
Num c = a + b;
std::cout << c.get() << "\n";
return 0;
}
Output:
30
The operator+ overload adds the two v members and returns a new Num. a + b calls a.operator+(b), producing Num(30). c.get() prints 30. Operator overloading lets user types use the same + syntax as built-ins.
30. What does this name-hiding print?
#include <iostream>
class Base {
public:
void f(int) { std::cout << "Base int\n"; }
};
class Derived : public Base {
public:
void f(double) { std::cout << "Derived double\n"; }
};
int main() {
Derived d;
d.f(5);
d.f(5.5);
return 0;
}
Output:
Derived double
Derived double
Derived::f(double) hides all Base::f overloads — name lookup finds Derived::f and stops; it does not consider the base overloads. So d.f(5) also resolves to Derived::f(double) (the int 5 converts to double), printing Derived double twice. To expose the base overloads you need using Base::f;. This is the classic C++ name-hiding interview question.
Premium Content
Unlock Output Questions - Part 2 and all premium lessons with a subscription.
From ₹199.99/year — See plans