How would you describe C++ and what programming paradigms does it support?
Answer
C++ extends C with object-oriented features (classes, inheritance, polymorphism) and generic programming (templates) while maintaining low-level control.
These are the C++ questions you'll encounter in technical interviews, each with a detailed written answer. Master memory management and pointers, then progress through STL, templates, and performance optimization.
C++ is a powerful, systems-level language that combines the efficiency of C with object-oriented features. It's used for high-performance applications, game engines, embedded systems, and competitive programming.
C++ interviews test your mastery of pointers, memory management, the Standard Template Library (STL), and performance optimization. You'll discuss RAII, move semantics, and how to write efficient, safe code.
C++ proficiency is critical for systems programming, game development, and high-frequency trading roles. Master the language and you'll tackle the most performance-critical challenges.
Reading answers is not the same as giving them. Sit a full mock interview and get scored on how you actually explain them.
Try a mock interviewAnswer
C++ extends C with object-oriented features (classes, inheritance, polymorphism) and generic programming (templates) while maintaining low-level control.
Answer
OOP bundles data and methods into objects, uses inheritance for code reuse, polymorphism for flexibility, encapsulation for data protection, and abstraction for interface simplification.
Answer
In C++, the only syntactic difference is default access: struct defaults to public, class defaults to private. Both support methods and inheritance.
Answer
Encapsulation hides internal state as private members and provides public interfaces (getters/setters) to control access and enforce class invariants.
Answer
Derived classes inherit members and can override methods. Single and multiple inheritance are supported, though multiple inheritance requires careful design.
Answer
Polymorphism enables writing code that works with base class references but executes derived class methods, allowing extensibility without modifying existing code.
Answer
Virtual functions use virtual tables (vtables) to store pointers to member functions, enabling dynamic dispatch where the correct method is called based on object type.
Answer
Templates generate type-specific code at compile time, enabling writing algorithms and containers that work with any type without runtime overhead.
Answer
STL includes containers (vector, map, set), algorithms (sort, find), iterators, and function objects enabling generic, efficient programming.
Answer
Exceptions propagate up the call stack until caught. RAII (destructors) ensure cleanup during unwinding, maintaining program invariants.
Answer
C++ extends C with object-oriented features including classes, inheritance, virtual functions, and polymorphism. It adds generic programming through templates, enabling type-safe code reuse without runtime overhead. C++ introduces new memory management with new/delete, RAII for resource management, and exceptions for error handling. While maintaining C's low-level features (pointers, manual memory control), C++ allows different programming styles: procedural (like C), object-oriented (classes and inheritance), generic (templates), and functional (lambdas, higher-order functions). This multi-paradigm approach makes C++ flexible for diverse applications.
Answer
Encapsulation bundles data with methods and hides implementation details using access specifiers (private, public, protected). Inheritance allows derived classes to extend base classes, promoting code reuse and creating hierarchies. Polymorphism enables methods to behave differently based on object type through function overloading (compile-time) and virtual functions (runtime). Abstraction presents simplified interfaces while hiding complexity. Together, these create maintainable, extensible code where changes to implementation don't affect client code.
Answer
Classes group related data (member variables) and operations (member functions) into a single unit. Access specifiers control visibility: private members are accessible only within the class, protecting internal state; public members define the interface for external code; protected members are accessible to derived classes. This separation enables encapsulation, allowing the class to maintain invariants and change internal implementation without affecting users.
Answer
Private members (data and methods) are inaccessible outside the class, protecting internal state. Public members form the official interface. Protected members allow derived classes to access and extend functionality. This hierarchy enforces encapsulation: clients use public methods (which validate input and maintain invariants), while implementation details remain private. Derived classes can access protected members for controlled extension.
Answer
Single inheritance derives from one base class, creating straightforward hierarchies. Multiple inheritance derives from multiple base classes, enabling combining different interfaces but causing ambiguity: if both parents have the same method, which is called? The diamond problem occurs when a grandparent class is inherited through two paths, duplicating its data. Virtual inheritance resolves this by sharing a single instance. Most modern design uses composition or interfaces (abstract base classes) instead of multiple inheritance due to complexity.
Answer
Compile-time polymorphism through function/operator overloading is resolved at compile time based on argument types. Multiple functions with the same name but different signatures coexist. Runtime polymorphism through virtual functions uses vtables to select the correct method at runtime based on object type. Template specialization is another compile-time mechanism. Compile-time polymorphism is zero-cost but less flexible; runtime is more flexible but has vtable overhead. Choosing between them depends on whether the type is known at compile time.
Answer
Classes with virtual functions maintain vtables mapping function names to pointers. When a virtual method is called on a base class pointer/reference, the program consults the object's vtable to find the actual method to execute. This enables calling derived class methods through base class references, achieving polymorphism. The first virtual function in a class adds a pointer to the vtable, increasing object size. Virtual destructors are crucial: without them, deleting a derived object through a base pointer won't call the derived destructor, causing resource leaks.
Answer
Templates are generic definitions that instantiate for specific types at compile time. Each template<typename T> function/class generates type-specific code. Template specialization allows providing custom implementations for specific types: partial specialization for type patterns, explicit specialization for exact types. Template metaprogramming uses templates to perform compile-time computations, generating code based on type properties. SFINAE (Substitution Failure Is Not An Error) uses template substitution failures to enable different code paths based on type traits, enabling sophisticated generic algorithms.
Answer
STL has three main components: Containers (vector, list, map, set) store collections. Algorithms (sort, find, transform) operate on containers. Iterators connect them, providing a common interface for traversal. A container provides begin()/end() iterators; algorithms accept iterators and work with any container. This separation enables algorithms to work with any container without coupling. Functors and lambdas customize algorithm behavior. STL achieves generic programming without inheritance, using templates and iterators.
Answer
When an exception is thrown, the program searches up the call stack for a matching catch block. During stack unwinding, local objects are destroyed (destructors called), ensuring cleanup. RAII (Resource Acquisition Is Initialization) ensures destructors free resources. Strong exception safety guarantees that operations succeed or have no effect. Basic exception safety guarantees the program remains valid but possibly changed. No-throw guarantee means the operation never throws. Best practices: catch by const reference, don't catch and ignore exceptions silently, use RAII for resource management, provide strong or basic exception safety guarantees.
This browser cannot record audio. Answer the question out loud anyway, then compare yourself against the model answer below.
Answer
I created a base Character class with virtual methods for movement, attacking, and taking damage. Derived classes (Warrior, Mage, Rogue) overrode these methods for specific behavior. Movement might be different speeds; attacks varied by damage type and range. Taking damage applied class-specific effects (Warrior gains armor, Mage loses mana). The client code worked with Character pointers, calling methods polymorphically. This design made adding new character types easy without changing existing code.
This browser cannot record audio. Answer the question out loud anyway, then compare yourself against the model answer below.
Answer
I created a generic Queue template that worked with any copyable type. For move-only types (like unique_ptr), I specialized the template to use move semantics. I used SFINAE to enable certain methods only for types supporting specific operations. I provided partial specialization for container types. Template metaprogramming helped ensure compile-time type safety. Testing required instantiating the template with various types.
This browser cannot record audio. Answer the question out loud anyway, then compare yourself against the model answer below.
Answer
I created a File class that opened files in the constructor and closed them in the destructor. Reading/writing happened in methods that checked if the file was open. If reading failed, methods threw exceptions, and the destructor guaranteed cleanup even during exception unwinding. This RAII pattern ensured resources were never leaked. Users didn't need try-catch for cleanup; the destructor handled it.
This browser cannot record audio. Answer the question out loud anyway, then compare yourself against the model answer below.
Answer
I debugged a crash where calling a virtual function on a deleted object caused undefined behavior. Using a debugger, I found the pointer was deleted but still used elsewhere. I tracked the object lifetime and found the deletion happened earlier than expected. I used unique_ptr with custom deleters to track when objects were destroyed. Adding virtual destructors to base classes prevented this class of bugs.
This browser cannot record audio. Answer the question out loud anyway, then compare yourself against the model answer below.
Answer
I created an Animation base template and specific animations (TranslateAnimation, RotateAnimation, FadeAnimation) derived from it. The AnimationSystem used a vector of Animation pointers and iterated through them calling update(). Animations could be composed in sequences using an AnimationSequence class that was also an Animation. This enabled flexible, reusable animation chains.
This browser cannot record audio. Answer the question out loud anyway, then compare yourself against the model answer below.
Answer
I used vector<int> to store data and stable_sort to sort by performance (keeping equal elements' order). I transformed results with transform() applying a filter function. I used find_if() to locate specific elements and copy_if() to extract a subset. STL algorithms are optimized and composable, making the code concise and efficient. I avoided manual loops.
This browser cannot record audio. Answer the question out loud anyway, then compare yourself against the model answer below.
Answer
Each transaction was atomic: validate input, execute, record. If any step threw, the transaction rolled back automatically through stack unwinding. I used unique_ptr for automatic cleanup during exceptions. I separated validation (which shouldn't throw) from execution. I caught specific exceptions at appropriate levels, not swallowing them. The account balance never ended in an inconsistent state.
This browser cannot record audio. Answer the question out loud anyway, then compare yourself against the model answer below.
Answer
I replaced copies with moves using move() and move semantics. I avoided unnecessary allocations by reserving vector capacity upfront. I used const references to avoid copying in function parameters. I eliminated temporaries by using expressions directly. Profiling showed a 3x speedup. Modern C++ features like auto, range-based for loops, and smart pointers made the code cleaner while being faster.
This browser cannot record audio. Answer the question out loud anyway, then compare yourself against the model answer below.
Answer
I encountered diamond inheritance where an Aircraft inherits from both Vehicle and Weaponized, both inheriting from Equipment. This duplicated Equipment's data and methods. I used virtual inheritance: class Vehicle : virtual public Equipment. This ensured only one copy of Equipment existed in the hierarchy. The virtual base constructor had to be explicitly called.
This browser cannot record audio. Answer the question out loud anyway, then compare yourself against the model answer below.
Answer
I wrapped a C library's opaque pointer handle in a C++ class. The constructor called the C library's initialization, storing the handle. The destructor called cleanup. Methods wrapped C functions, translating between C++ types and C types. I used smart pointers to ensure cleanup even if exceptions occurred. This made the C library feel like idiomatic C++.
class Vector2D {
private:
double x, y;
public:
Vector2D(double x = 0, double y = 0) : x(x), y(y) {}
// Implement operators and methods
};Answer
class Vector2D {
private:
double x, y;
public:
Vector2D(double x = 0, double y = 0) : x(x), y(y) {}
Vector2D operator+(const Vector2D& other) const {
return Vector2D(x + other.x, y + other.y);
}
Vector2D operator-(const Vector2D& other) const {
return Vector2D(x - other.x, y - other.y);
}
double dot(const Vector2D& other) const {
return x * other.x + y * other.y;
}
};class Animal {
public:
virtual ~Animal() {}
virtual void speak() = 0;
// Add more virtual methods
};Answer
class Animal {
public:
virtual ~Animal() {}
virtual void speak() const = 0;
};
class Dog : public Animal {
public:
void speak() const override { std::cout << "Woof!" << std::endl; }
};
class Cat : public Animal {
public:
void speak() const override { std::cout << "Meow!" << std::endl; }
};template<typename T>
class LinkedList {
private:
struct Node { T data; Node* next; };
Node* head;
public:
LinkedList() : head(nullptr) {}
// Implement list operations
};Answer
template<typename T>
class LinkedList {
private:
struct Node { T data; Node* next; };
Node* head;
public:
LinkedList() : head(nullptr) {}
~LinkedList() { while (head) { Node* temp = head; head = head->next; delete temp; } }
void push(const T& value) {
Node* newNode = new Node{value, head};
head = newNode;
}
bool pop() {
if (!head) return false;
Node* temp = head;
head = head->next;
delete temp;
return true;
}
};#include <memory>
class ResourceManager {
private:
std::unique_ptr<Resource> exclusive;
std::vector<std::shared_ptr<Resource>> shared;
public:
// Implement resource management
};Answer
#include <memory>
class ResourceManager {
private:
std::unique_ptr<Resource> exclusive;
std::vector<std::shared_ptr<Resource>> shared;
public:
void addExclusive(std::unique_ptr<Resource> res) { exclusive = std::move(res); }
void addShared(std::shared_ptr<Resource> res) { shared.push_back(res); }
};class DivisionByZero : public std::exception {
public:
const char* what() const noexcept { return "Division by zero"; }
};
class Calculator {
public:
double divide(double a, double b) {
// Implement with exception throwing
}
};Answer
class DivisionByZero : public std::exception {
public:
const char* what() const noexcept { return "Division by zero"; }
};
class Calculator {
public:
double divide(double a, double b) {
if (b == 0) throw DivisionByZero();
return a / b;
}
};class Complex {
private:
double real, imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
// Overload arithmetic operators
};Answer
class Complex {
private:
double real, imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
Complex operator+(const Complex& other) const {
return Complex(real + other.real, imag + other.imag);
}
Complex operator*(const Complex& other) const {
return Complex(real * other.real - imag * other.imag, real * other.imag + imag * other.real);
}
};#include <vector>
#include <algorithm>
struct Product { std::string name; double price; };
void processProducts(std::vector<Product>& products) {
// Sort and filter using STL algorithms
}Answer
#include <vector>
#include <algorithm>
struct Product { std::string name; double price; };
void processProducts(std::vector<Product>& products) {
std::sort(products.begin(), products.end(), [](const Product& a, const Product& b) {
return a.price < b.price;
});
auto it = std::remove_if(products.begin(), products.end(), [](const Product& p) {
return p.price > 100;
});
products.erase(it, products.end());
}#include <fstream>
class File {
private:
std::ifstream file;
public:
File(const std::string& path) {
file.open(path);
if (!file) throw std::runtime_error("Cannot open file");
}
~File() { file.close(); }
// Add read methods
};Answer
#include <fstream>
class File {
private:
std::ifstream file;
public:
File(const std::string& path) {
file.open(path);
if (!file) throw std::runtime_error("Cannot open");
}
~File() { file.close(); }
std::string readLine() {
std::string line;
std::getline(file, line);
return line;
}
};class String {
private:
char* data;
size_t length;
public:
String(const String& other);
String(String&& other) noexcept;
String& operator=(String&& other) noexcept;
};Answer
class String {
private:
char* data;
size_t length;
public:
String(String&& other) noexcept : data(other.data), length(other.length) {
other.data = nullptr; other.length = 0;
}
String& operator=(String&& other) noexcept {
if (this != &other) {
delete[] data;
data = other.data; length = other.length;
other.data = nullptr; other.length = 0;
}
return *this;
}
};template<typename T, typename U>
class Pair {
public:
T first; U second;
};
// Provide specialization for pointer types
template<typename T, typename U>
class Pair<T*, U*> {
// Specialized implementation
};Answer
template<typename T, typename U>
class Pair {
public:
T first; U second;
};
template<typename T, typename U>
class Pair<T*, U*> {
public:
T* first; U* second;
~Pair() { delete first; delete second; }
};