Top 42 C++ Programming Interview Questions and Answers
Dec 16, 2024 14 Min Read 272 Views
(Last Updated)
Mastering C++ is no small feat, but when it comes to acing interviews, it’s essential to not only understand the fundamentals but also dive deep into the intricacies of this powerful language. C++ remains a cornerstone in the tech industry, used extensively for game development, high-performance applications, and system-level programming.
Whether you’re a budding programmer or an experienced developer preparing for your next career move, having a solid grasp of C++ interview questions is your ticket to standing out.
In this guide, I’ve brought together a list of the Top 40 C++ Programming Interview Questions and Answers, meticulously divided into beginner, intermediate, and advanced levels after thorough research. Covering both theoretical concepts and practical coding challenges, this list will help you gain insights and problem-solving skills needed to impress your interviewer and land that dream role.
Table of contents
- Top C++ Programming Interview Questions and Answers (Section-Wise)
- Beginner Level C++ Programming Interview Questions and Answers
- Intermediate Level C++ Programming Interview Questions and Answers
- Advanced Level C++ Programming Interview Questions and Answers
- Concluding Thoughts…
Top C++ Programming Interview Questions and Answers (Section-Wise)
I have divided all these important C++ Programming interview questions and answers into various sections for your ease of learning, I recommend covering the beginner-level questions as a must and then going through all the sections one by one so that you can gain a well-rounded knowledge of how these interviews are undertaken and how much and what you should prepare.
Beginner Level C++ Programming Interview Questions and Answers
1. What is C++ and how is it different from C?
Answer:
C++ is an object-oriented programming language that extends C. Differences include:
- Object-Oriented Features: Supports classes, objects, inheritance, and polymorphism.
- Function Overloading and Templates: Enables code reuse.
- STL (Standard Template Library): Provides data structures and algorithms.
- Namespace Support: Prevents name conflicts.
- Inline Functions: Reduces function call overhead.
2. What are the key features of C++?
Answer:
- Object-Oriented Programming: Supports encapsulation, inheritance, and polymorphism.
- Templates: Generic programming via function and class templates.
- STL: Provides reusable libraries for containers, algorithms, and iterators.
- Platform Independence: Compiled code is OS-independent.
- Low-Level Manipulation: Supports pointer arithmetic and memory management.
3. What is the difference between a class and an object?
Answer:
- Class: A blueprint or template that defines attributes and behaviors.
Object: An instance of a class.
class Car { // Class definition
public:
string model;
void drive() { cout << "Driving " << model; }
};
Car c; // Object instantiation
4. Explain the concept of a constructor in C++.
Answer:
A constructor is a special member function with the same name as the class. It initializes objects.
- Default Constructor: Takes no arguments.
- Parameterized Constructor: Accepts arguments.
Copy Constructor: Initializes an object from another object of the same class.
class MyClass {
public:
MyClass() { cout << "Default constructor"; }
MyClass(int x) { cout << "Parameterized constructor: " << x; }
MyClass(const MyClass &obj) { cout << "Copy constructor"; }
};
5. What is a destructor in C++?Answer:
A destructor in C++ is a special member function called when an object is destroyed. It cleans up resources.
class MyClass {
public:
~MyClass() { cout << "Destructor called"; }
};
6. What is the difference between struct and class in C++?
Answer:
Aspect | struct | class |
Default Access | Members are public by default. | Members are private by default. |
Purpose | Primarily used for simple data grouping. | Used for complex object modeling and encapsulation. |
Inheritance | Inherits publicly by default. | Inherits privately by default. |
Encapsulation | Limited due to default public access. | Fully supports encapsulation. |
Use Case | Lightweight, for plain data structures. | Full-featured objects with methods and access control. |
Key Insight:
Both are almost identical in C++ except for the default access specifier and typical use cases. Classes are preferred for object-oriented programming, while structs are used for simpler tasks.
7. What is function overloading?
Answer:
Function overloading is a feature in C++ that allows multiple functions with the same name to coexist in a program, differentiated by their parameter lists. The compiler distinguishes between these functions based on the number, types, or order of their parameters (also known as the function’s signature).
Key Points:
- Enhances code readability and reusability.
- Does not depend on the return type of the function.
- Achieved through compile-time polymorphism.
Example:
#include <iostream>
using namespace std;
void display(int x) {
cout << "Integer: " << x << endl;
}
void display(double x) {
cout << "Double: " << x << endl;
}
int main() {
display(10); // Calls display(int)
display(10.5); // Calls display(double)
return 0;
}
8. Explain default arguments in functions.
Answer:
- Definition: Default arguments allow functions to use predefined values if no corresponding argument is passed by the caller.
- Key Points:
- Default arguments are defined in the function declaration.
- They must be assigned from right to left in the parameter list.
Example:
void greet(string name = "Guest") {
cout << "Hello, " << name << endl;
}
greet(); // Output: Hello, Guest
greet("Alice"); // Output: Hello, Alice
9. What are inline functions?
Answer:
Definition: Inline functions are small functions suggested to the compiler to expand directly at the point of call instead of using the typical function call mechanism.
Key Points:
- Declared using the inline keyword.
- Helps reduce function call overhead for small, frequently used functions.
- The compiler may ignore the inline request based on function complexity.
Example:
inline int square(int x) {
return x * x;
}
cout << square(4); // Output: 16
10. Explain the concept of namespaces in C++.
Answer:
Definition: Namespaces provide a way to group related identifiers (like classes, variables, and functions) to avoid naming conflicts in large projects.
Key Points:
- Declared using the namespace keyword.
- Accessed using the scope resolution operator (::).
Example:
namespace Math {
int add(int a, int b) { return a + b; }
}
cout << Math::add(3, 5); // Output: 8
The std namespace, which contains the Standard Library, is a common example.
11. Write a program to swap two numbers using a temporary variable.
Answer:
#include <iostream>
using namespace std;
int main() {
int a = 5, b = 10;
cout << "Before Swap: a = " << a << ", b = " << b << endl;
int temp = a; // Store value of a in temp
a = b; // Assign value of b to a
b = temp; // Assign value of temp to b
cout << "After Swap: a = " << a << ", b = " << b << endl;
return 0;
}
Output:
less
Copy code
Before Swap: a = 5, b = 10
After Swap: a = 10, b = 5
Explanation:
- Store the value of a in temp.
- Assign the value of b to a.
- Assign the value of temp (original value of a) to b.
12. What is the purpose of the sizeof operator in C++?
Answer:
The sizeof operator in C++ is used to determine the size, in bytes, of a data type, variable, or object at compile time. It helps in understanding memory allocation and is often used for low-level programming tasks like memory management or working with hardware.
Example:
#include <iostream>
using namespace std;
int main() {
cout << "Size of int: " << sizeof(int) << " bytes\n"; // Typically 4 bytes
cout << "Size of double: " << sizeof(double) << " bytes\n"; // Typically 8 bytes
return 0;
}
Key Features:
- Evaluated at compile time.
- Includes padding bytes for structure alignment.
- Commonly used for array size calculation and type alignment.
Intermediate Level C++ Programming Interview Questions and Answers
13. What is the difference between new and malloc?
Answer:
Aspect | new | malloc |
Type Safety | Returns a pointer of the correct type. | Returns a void*; requires casting. |
Initialization | Initializes objects (calls constructor). | Does not initialize memory. |
Deallocation | Uses delete (calls destructor). | Uses free, no destructor called. |
Overloadable | Can be overloaded in C++. | Cannot be overloaded. |
Key Takeaway:
- Use new in C++ for better type safety and automatic initialization.
- malloc is more common in C or mixed-language projects where constructors/destructors are not required.
14. Explain the concept of operator overloading.
Answer:
Operator overloading allows developers to redefine the behavior of operators (e.g., +, -) for user-defined types.
- Enables intuitive operations with objects, like adding two custom Matrix objects.
- Achieved by defining a function using the operator keyword.
Example:
class Complex {
double real, imag;
public:
Complex(double r, double i) : real(r), imag(i) {}
Complex operator+(const Complex &c) {
return Complex(real + c.real, imag + c.imag);
}
};
15. What are static variables and functions in C++?
Answer:
- Static Variables:
- Have a single instance shared across all objects.
- Retain their value between function calls.
- Static Functions:
- Associated with the class, not objects.
- Can access only static data members or other static functions.
Example:
class Counter {
static int count;
public:
static void increment() { count++; }
static int getCount() { return count; }
};
int Counter::count = 0;
16. Explain this pointer in detail.
Answer:
- A pointer to the current object in a member function.
- Used to access or modify the calling object.
- Implicitly passed to all non-static member functions.
Example:
class Demo {
int x;
public:
Demo& setX(int x) {
this->x = x;
return *this;
}
};
17. What is dynamic memory allocation in C++?
Answer:
- Allocating memory during runtime using new or malloc.
- Enables creation of flexible and resizable data structures like arrays or linked lists.
- Must be deallocated using delete or free to avoid memory leaks.
Example:
int* ptr = new int[5]; // Dynamic array
delete[] ptr; // Deallocate
18. Write a program to implement a simple stack using a class.
Answer:
#include <iostream>
using namespace std;
class Stack {
int *arr, top, size;
public:
Stack(int s) : size(s), top(-1) { arr = new int[s]; }
~Stack() { delete[] arr; }
void push(int val) {
if (top < size - 1) arr[++top] = val;
else cout << "Stack Overflow\n";
}
int pop() {
return (top >= 0) ? arr[top--] : -1;
}
bool isEmpty() { return top == -1; }
};
int main() {
Stack s(3);
s.push(10);
s.push(20);
s.push(30);
cout << s.pop() << endl; // Output: 30
cout << s.pop() << endl; // Output: 20
}
What’s happening:
- Class Structure:
- The class has a dynamically allocated array arr to store stack elements, and variables top (current position) and size (maximum stack size).
- Constructor:
- Allocates memory for the stack of specified size.
- Destructor:
- Frees allocated memory to prevent memory leaks.
- Push Operation:
- Adds an element to the stack if it isn’t full.
- Prints “Stack Overflow” if the stack is full.
- Pop Operation:
- Removes and returns the top element if the stack isn’t empty.
- Returns -1 if the stack is empty.
- isEmpty Method:
- Checks whether the stack is empty.
This program demonstrates the basic operations of a stack in a concise and efficient manner.
19. Explain the difference between deep copy and shallow copy.
Answer:
Aspect | Shallow Copy | Deep Copy |
Definition | Copies only the reference or pointer to the original memory. | Copies both the reference and the actual data, creating a separate memory block. |
Memory Sharing | The original and the copied object share the same memory. | The copied object has its own separate memory allocation. |
Use Case | Faster, suitable for immutable or read-only data. | Safer for mutable data to avoid accidental modifications. |
Risk of Issues | Changes in one object affect the other. | No such risk as each object is independent. |
Implementation | Default behavior of copy constructors or assignment operators. | Custom implementation using deep copy logic. |
Shallow Copy:
class Shallow {
int* data;
public:
Shallow(int val) { data = new int(val); }
~Shallow() { delete data; }
Shallow(const Shallow& obj) { data = obj.data; } // Copies the pointer only
};
Issue: If one object modifies or deletes the memory, the other is affected, leading to potential crashes or unexpected behavior.
Deep Copy:
class Deep {
int* data;
public:
Deep(int val) { data = new int(val); }
~Deep() { delete data; }
Deep(const Deep& obj) { data = new int(*obj.data); } // Allocates new memory and copies the value
};
Advantage: Each object maintains its own memory, ensuring no unintended interactions between objects.
Key Takeaway:
- Use shallow copy for lightweight, read-only operations.
- Use deep copy when working with mutable or complex objects to avoid shared state issues.
20. How does virtual inheritance solve the diamond problem?
Answer:
The Diamond Problem
- Scenario: In a class hierarchy, a class (e.g., D) inherits from two classes (B and C), both of which inherit from a common base class (A).
- Problem: D ends up with two copies of A, leading to ambiguity when accessing members of A.
Solution with Virtual Inheritance
- Virtual Inheritance ensures that the derived class (D) inherits only one shared instance of the common base class (A), eliminating duplication.
- Introduced using the virtual keyword in the base class inheritance declaration.
Implementation:
#include <iostream>
using namespace std;
class A {
public:
int value;
A() : value(0) {}
};
class B : virtual public A {}; // Virtual inheritance
class C : virtual public A {}; // Virtual inheritance
class D : public B, public C {};
int main() {
D obj;
obj.value = 10; // No ambiguity due to single shared instance of A
cout << "Value: " << obj.value << endl; // Output: 10
return 0;
}
How It Works:
- Single Instance: B and C share a single instance of A through virtual inheritance, avoiding duplication.
- Unambiguous Access: Members of A are directly accessible to D without ambiguity.
- Efficiency: Reduces memory overhead and avoids inconsistent states caused by multiple copies of the base class.
So basically, virtual inheritance ensures a single, shared instance of the common base class, resolving ambiguities in the diamond problem and maintaining proper class hierarchy.
21. What are friend functions in C++?
Answer:
A friend function is a function that is not a member of a class but has access to the class’s private and protected members.
- Declared using the friend keyword within the class.
Key Points:
- Non-Member Access: Allows external functions to access private/protected data of the class.
- Syntax:
class ClassName {
friend ReturnType FriendFunction(Parameters);
};
- Use Case: Commonly used to implement operator overloading and provide controlled access to class internals.
Example:
#include <iostream>
using namespace std;
class Box {
int length;
public:
Box(int l) : length(l) {}
friend int getLength(Box b); // Friend function declaration
};
int getLength(Box b) { // Friend function definition
return b.length;
}
int main() {
Box b(10);
cout << "Length: " << getLength(b) << endl; // Output: Length: 10
return 0;
}
Hence, friend functions provide flexibility for non-member functions to interact closely with class data while preserving encapsulation in other scenarios.
22. What is the difference between function overloading and function overriding?
Answer:
Aspect | Function Overloading | Function Overriding |
Definition | Defining multiple functions with the same name but different parameters in the same scope. | Redefining a base class function in the derived class with the same signature. |
Scope | Occurs within the same class. | Occurs between base and derived classes. |
Parameters | Must differ in the number or type of parameters. | Must have the exact same parameters as the base class function. |
Return Type | Can differ but does not play a role in resolution. | Must have the same return type for polymorphism. |
Behavior | Achieves compile-time polymorphism. | Achieves runtime polymorphism via virtual functions. |
Keyword Use | No special keyword is needed. | Uses the virtual keyword in the base class function. |
Overloading:
class Example {
public:
void display(int a) { cout << "Integer: " << a << endl; }
void display(double a) { cout << "Double: " << a << endl; }
};
Overriding:
class Base {
public:
virtual void show() { cout << "Base class show" << endl; }
};
class Derived : public Base {
public:
void show() override { cout << "Derived class show" << endl; }
};
Overloading enables functions with the same name but different arguments for compile-time flexibility whilst Overriding redefines base class behavior in derived classes for runtime polymorphism.
23. Write a program to implement a queue using an array.
Answer:
#include <iostream>
using namespace std;
class Queue {
int *arr, front, rear, size, capacity;
public:
Queue(int cap) : front(0), rear(-1), size(0), capacity(cap) {
arr = new int[cap];
}
void enqueue(int x) {
if (size == capacity) { cout << "Queue Full\n"; return; }
rear = (rear + 1) % capacity;
arr[rear] = x;
size++;
}
void dequeue() {
if (size == 0) { cout << "Queue Empty\n"; return; }
front = (front + 1) % capacity;
size--;
}
void display() {
for (int i = 0; i < size; i++)
cout << arr[(front + i) % capacity] << " ";
cout << endl;
}
};
int main() {
Queue q(3);
q.enqueue(10); q.enqueue(20); q.enqueue(30);
q.display(); // Output: 10 20 30
q.dequeue(); q.display(); // Output: 20 30
}
24. Explain the purpose of explicit keyword.
Answer:
Prevents implicit conversions for constructors or type casting.
class MyClass {
public:
explicit MyClass(int x) { cout << x; }
};
MyClass obj1 = 10; // Error without explicit
MyClass obj2(10); // Works
25. What are smart pointers in C++?
Answer:
Smart pointers manage dynamic memory and prevent leaks.
- std::unique_ptr: Ownership restricted to one pointer.
- std::shared_ptr: Shared ownership.
std::weak_ptr: Non-owning reference.
#include <memory>
auto p = std::make_unique<int>(10);
26. Write a program to check if a string is a palindrome.
Answer:
#include <iostream>
using namespace std;
bool isPalindrome(const string &str) {
int start = 0, end = str.size() - 1;
while (start < end) {
if (str[start++] != str[end--]) return false;
}
return true;
}
int main() {
string s = "radar";
cout << (isPalindrome(s) ? "Yes" : "No"); // Output: Yes
}
27. Explain the working of std::map and its time complexity.
Answer:
std::map is an associative container that stores key-value pairs, where each key is unique. Internally, it is implemented as a self-balancing binary search tree (commonly a Red-Black Tree). This allows it to maintain the elements in sorted order based on the keys.
Key Features:
- Key-Value Pair Storage: Each element in std::map consists of a pair: a key and a corresponding value.
- Automatic Sorting: Keys are automatically sorted according to the comparison function (by default, using the < operator).
- Unique Keys: Duplicate keys are not allowed; if you attempt to insert a pair with an existing key, the insertion fails.
Time Complexity of std::map Operations:
- Insertion (insert): O(log n)
- Inserting a key-value pair into the map involves finding the correct position in the tree (logarithmic time complexity).
- Search (find): O(log n)
- Searching for a value associated with a key also requires traversing the tree, which is done in logarithmic time.
- Deletion (erase): O(log n)
- Deleting an element involves finding the key and then balancing the tree, which also takes logarithmic time.
- Accessing Elements (operator[] or at): O(log n)
- Accessing a value via its key requires searching for the key in the tree, which is done in logarithmic time.
Would you like to nail these C++ Interviews? GUVI’s C++ Programming Course is designed for learners aiming to master C++ and prepare for programming interviews. This course offers hands-on experience with core C++ concepts, algorithms, data structures, and problem-solving techniques.
Key features include personalized mentoring, interactive assignments, quizzes, and access to a strong community of learners. It also covers essential interview preparation strategies and coding challenges.
You will benefit from tools like IDE support, real-time code execution, and detailed explanations to improve your coding skills effectively. Perfect for beginners and intermediate learners, this course provides the practical knowledge needed to excel in C++ programming interviews.
Advanced Level C++ Programming Interview Questions and Answers
28. Write a program to implement Depth First Search (DFS) on a graph.
Answer:
#include <iostream>
#include <vector>
using namespace std;
void DFS(int node, vector<vector<int>> &adj, vector<bool> &visited) {
visited[node] = true;
cout << node << " ";
for (int neighbor : adj[node])
if (!visited[neighbor]) DFS(neighbor, adj, visited);
}
int main() {
int n = 5; // Number of nodes
vector<vector<int>> adj(n);
adj[0] = {1, 2}; adj[1] = {0, 3}; adj[2] = {0}; adj[3] = {1, 4}; adj[4] = {3};
vector<bool> visited(n, false);
DFS(0, adj, visited); // Output: 0 1 3 4 2
return 0;
}
29. What is the difference between compile-time and runtime polymorphism?
Answer:
Aspect | Compile-time Polymorphism | Runtime Polymorphism |
Definition | Occurs when function calls are resolved at compile time. | Occurs when function calls are resolved at runtime. |
Mechanism | Achieved through function overloading or operator overloading. | Achieved through method overriding using virtual functions. |
Binding | Static binding (early binding). | Dynamic binding (late binding). |
Performance | Faster, as it is resolved at compile time. | Slightly slower due to overhead of dynamic lookup at runtime. |
Flexibility | Less flexible; requires all decisions to be made at compile time. | More flexible; decisions are made at runtime, allowing for dynamic behavior. |
Example | Function overloading, operator overloading. | Method overriding using virtual keyword. |
Compile-time Polymorphism (Function Overloading):
class Example {
public:
void print(int i) { cout << "Integer: " << i << endl; }
void print(double d) { cout << "Double: " << d << endl; }
};
Runtime Polymorphism (Method Overriding):
class Base {
public:
virtual void display() { cout << "Base Class Display" << endl; }
};
class Derived : public Base {
public:
void display() override { cout << "Derived Class Display" << endl; }
};
So basically, Compile-time polymorphism is resolved at compile time through function/ operator overloading, while runtime polymorphism is resolved at runtime using method overriding with virtual functions.
30. Write a program to implement a simple Binary Search Tree (BST).
Answer:
#include <iostream>
using namespace std;
struct Node {
int data;
Node *left, *right;
Node(int val) : data(val), left(nullptr), right(nullptr) {}
};
Node* insert(Node* root, int val) {
if (!root) return new Node(val);
if (val < root->data) root->left = insert(root->left, val);
else root->right = insert(root->right, val);
return root;
}
void inOrder(Node* root) {
if (!root) return;
inOrder(root->left);
cout << root->data << " ";
inOrder(root->right);
}
int main() {
Node* root = nullptr;
root = insert(root, 5);
insert(root, 3); insert(root, 7); insert(root, 2); insert(root, 4);
inOrder(root); // Output: 2 3 4 5 7
}
31. Explain the concept of move semantics and rvalue references.
Answer:
Move Semantics:
- Purpose: Optimizes performance by transferring resources (like memory or file handles) from one object to another instead of copying them.
- How: Allows an object to “move” its resources to another object, making the original object empty or in a valid but unspecified state. This avoids expensive deep copies.
Rvalue References:
- Syntax: Represented by && (e.g., int&&).
- What They Are: Rvalue references bind to temporary objects (rvalues), which are objects that are about to be destroyed.
- Usage: They enable “move” operations by allowing the transfer of resources from one object to another without copying.
Move Constructor & Move Assignment Operator:
- Move constructor and move assignment operator are special functions that implement move semantics. They take rvalue references as arguments and “move” the resource ownership.
Example:
#include <iostream>
#include <vector>
using namespace std;
class MyClass {
vector<int> data;
public:
MyClass(vector<int>&& vec) : data(move(vec)) {} // Move constructor
void display() { for (int i : data) cout << i << " "; cout << endl; }
};
int main() {
vector<int> v = {1, 2, 3};
MyClass obj(move(v)); // Move resources from 'v' to 'obj'
obj.display(); // Output: 1 2 3
// 'v' is now empty, as its resources were moved to 'obj'
}
What you must understand:
- Rvalue References: Enable efficient resource transfers without copying.
- Move Semantics: Improve performance by transferring ownership, especially for resource-heavy objects (e.g., containers).
- Efficiency: Reduces unnecessary copying, resulting in faster code and lower memory usage.
32. What is the difference between std::vector and std::list?
Answer:
Aspect | std::vector | std::list |
Data Structure | Dynamic array (contiguous memory) | Doubly linked list (non-contiguous memory) |
Access Time | Constant time (O(1)) for random access. | Linear time (O(n)) for random access. |
Insertion/Deletion | Efficient at the end (O(1)), slow in the middle/beginning (O(n)). | Efficient at both ends (O(1)), slow in the middle (O(n)). |
Memory Usage | More compact (single block of memory). | Requires extra memory for pointers (for each element). |
Performance | Best for frequent access and appending to the end. | Best for frequent insertions and deletions at both ends. |
Iteration | Linear time (O(n)) for iteration. | Linear time (O(n)) for iteration, but more pointer dereferencing. |
Use Case:
- std::vector: Best when you need fast random access and need to frequently append or access elements by index.
- std::list: Best when you need frequent insertions and deletions at both ends or in the middle, but you don’t need fast random access.
33. Write a program to detect a cycle in a linked list.
Answer:
#include <iostream>
using namespace std;
struct Node {
int data;
Node* next;
Node(int val) : data(val), next(nullptr) {}
};
bool hasCycle(Node* head) {
Node *slow = head, *fast = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
if (slow == fast) return true;
}
return false;
}
34. What is a lambda function in C++?
Answer:
A lambda function in C++ is an anonymous (unnamed) function that can be defined inline, allowing for quick, concise function creation. Lambda functions are particularly useful for short operations, often passed as arguments to algorithms or used in situations where a function is needed temporarily.
Syntax:
[ capture_clause ] ( parameter_list ) -> return_type { body }
- Capture Clause: Captures variables from the surrounding scope (by value [=] or by reference [&]).
- Parameter List: Optional parameters for the lambda.
- Return Type: Optional; inferred if not specified.
- Body: The code to be executed.
Example:
#include <iostream>
using namespace std;
int main() {
int x = 10;
auto add = [](int y) { return x + y; }; // Lambda function
cout << add(5); // Output: 15
}
Explanation:
- add is a lambda function that takes an integer y and returns the sum of x and y.
- The lambda captures the value of x by reference (default capture [=] means capturing by value).
35. Explain the purpose of std::move.
Answer:
std::move is used to enable move semantics in C++. It allows the efficient transfer of resources (like memory or file handles) from one object to another, rather than copying the data.
- Move semantics reduce unnecessary copies and improve performance, especially when dealing with temporary objects.
- It casts an object to an r-value reference, signaling that its resources can be moved (rather than copied).
Example:
#include <iostream>
#include <vector>
void transfer(std::vector<int>&& v) {
std::vector<int> newVec = std::move(v); // Moves resources from v to newVec
// Now v is in an unspecified state
}
int main() {
std::vector<int> vec = {1, 2, 3};
transfer(std::move(vec)); // vec is now empty, resources moved
}
36. Write a program to find the shortest path using Dijkstra’s algorithm.
Answer:
#include <iostream>
#include <climits>
#include <vector>
using namespace std;
#define V 9 // Number of vertices in graph
// Function to find the vertex with the minimum distance value
int minDistance(vector<int>& dist, vector<bool>& sptSet) {
int min = INT_MAX, min_index;
for (int v = 0; v < V; v++) {
if (!sptSet[v] && dist[v] <= min) {
min = dist[v];
min_index = v;
}
}
return min_index;
}
// Function to implement Dijkstra's algorithm
void dijkstra(int graph[V][V], int src) {
vector<int> dist(V, INT_MAX); // Distance from source to each vertex
vector<bool> sptSet(V, false); // Shortest path tree set
dist[src] = 0;
for (int count = 0; count < V - 1; count++) {
int u = minDistance(dist, sptSet); // Get vertex with minimum distance
sptSet[u] = true;
// Update dist value of adjacent vertices
for (int v = 0; v < V; v++) {
if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX && dist[u] + graph[u][v] < dist[v]) {
dist[v] = dist[u] + graph[u][v];
}
}
}
// Print the constructed distance array
cout << "Vertex \t\t Distance from Source" << endl;
for (int i = 0; i < V; i++) {
cout << i << " \t\t " << dist[i] << endl;
}
}
int main() {
int graph[V][V] = { {0, 4, 0, 0, 0, 0, 0, 8, 0},
{4, 0, 8, 0, 0, 0, 0, 0, 0},
{0, 8, 0, 7, 0, 4, 0, 0, 2},
{0, 0, 7, 0, 9, 14, 0, 0, 0},
{0, 0, 0, 9, 0, 10, 0, 0, 0},
{0, 0, 4, 14, 10, 0, 2, 0, 0},
{0, 0, 0, 0, 0, 2, 0, 1, 6},
{8, 0, 0, 0, 0, 0, 1, 0, 7},
{0, 0, 2, 0, 0, 0, 6, 7, 0} };
dijkstra(graph, 0); // Source vertex is 0
return 0;
}
Explanation:
- Graph Representation: The graph is represented using a 2D adjacency matrix, where graph[i][j] holds the weight of the edge between vertices i and j.
- Dijkstra’s Algorithm:
- minDistance(): Finds the vertex with the minimum distance value that hasn’t been processed yet.
- dijkstra(): Implements the algorithm, updating the shortest distance to each vertex from the source. It uses a greedy approach, choosing the next vertex with the smallest tentative distance and updating the distances of its neighbors.
- Output: The program prints the shortest distance from the source to every other vertex.
Example Output:
Vertex Distance from Source
0 0
1 4
2 12
3 19
4 21
5 11
6 9
7 8
8 14
This program efficiently computes the shortest path from a source vertex to all other vertices using Dijkstra’s algorithm.
37. What are volatile variables in C++?
Answer:
- Definition: A volatile variable is a type qualifier used in C++ to indicate that a variable’s value may be changed by external factors beyond the program’s control (e.g., hardware, interrupts, or multi-threaded environments).
- Purpose: It prevents the compiler from optimizing the variable by assuming its value will remain constant, ensuring that the program always fetches the most up-to-date value of the variable from memory.
- Usage:
- Commonly used for variables that are modified by interrupt service routines (ISRs), hardware registers, or other threads in multi-threaded applications.
- Tells the compiler not to cache the variable’s value in registers and forces it to access the variable’s memory location each time it is referenced.
Example:
volatile int flag = 0;
void interrupt_handler() {
flag = 1; // Interrupt modifies 'flag'
}
int main() {
while (!flag) {
// Wait for interrupt to set 'flag' to 1
}
// Proceed once 'flag' becomes 1
}
Key Points:
- Prevents Optimization: Without volatile, the compiler might assume that flag does not change and could optimize the loop inappropriately.
- Not Thread-Safe: volatile does not guarantee atomicity or synchronization in multi-threaded programs. For thread safety, other synchronization mechanisms like mutexes should be used.
38. How does RAII (Resource Acquisition Is Initialization) work in C++?
Answer:
RAII is a programming idiom used in C++ where resource allocation (e.g., memory, file handles, locks) is tied to the lifetime of an object. The basic principle is that resources are acquired during object construction and released during object destruction.
How it works:
- Resource Allocation: When an object is created, it allocates the required resource (e.g., opening a file or allocating memory).
- Resource Release: When the object goes out of scope, its destructor automatically releases the resource (e.g., closing the file or freeing memory).
- Automatic Cleanup: The key advantage of RAII is that it ensures resources are properly released without the need for explicit cleanup code, avoiding memory leaks or resource mismanagement.
Example:
#include <iostream>
#include <fstream>
class FileHandler {
std::fstream file;
public:
FileHandler(const std::string& filename) {
file.open(filename, std::ios::out);
if (!file) {
std::cerr << "File open failed!" << std::endl;
}
}
~FileHandler() {
if (file.is_open()) {
file.close(); // Resource (file) is released here
}
}
};
int main() {
FileHandler fh("example.txt"); // File is opened during construction
// File will be automatically closed when fh goes out of scope
}
RAII ensures that resources are managed safely and automatically, leveraging C++ constructors and destructors to handle allocation and cleanup, reducing the risk of resource leaks.
39. What are condition variables in multithreading?
Answer:
A condition variable is a synchronization primitive used in multithreading to allow threads to wait for certain conditions to be met before proceeding. It is typically used in scenarios where threads need to wait for specific conditions to be true before continuing execution (such as waiting for a resource to become available or a computation to complete).
Key Points:
- Usage: Condition variables are used in combination with mutexes to synchronize threads and control access to shared resources.
- Functions:
- wait(): Puts the calling thread into a waiting state until it is notified.
- notify_one(): Wakes up one thread waiting on the condition variable.
- notify_all(): Wakes up all threads waiting on the condition variable.
- Typical Scenario: A thread may wait for a condition to be met (e.g., a buffer being non-empty), and once that condition is satisfied, another thread will notify the waiting thread.
Example:
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;
mutex mtx;
condition_variable cv;
bool ready = false;
void print_id(int id) {
unique_lock<mutex> lck(mtx);
while (!ready) cv.wait(lck); // Wait until ready is true
cout << "Thread " << id << '\n';
}
void go() {
unique_lock<mutex> lck(mtx);
ready = true;
cv.notify_all(); // Notify all threads
}
int main() {
thread threads[10];
for (int i = 0; i < 10; ++i)
threads[i] = thread(print_id, i);
cout << "Waiting to start...\n";
this_thread::sleep_for(chrono::seconds(1));
go(); // Notify all threads to start
for (auto& th : threads) th.join();
}
Explanation:
- print_id(): Each thread waits for the ready condition to be true before printing its ID.
- go(): Once the condition is set to true, notify_all() wakes up all waiting threads.
Condition variables are used to synchronize threads by enabling one thread to wait for a condition and another to notify waiting threads once the condition is met, ensuring smooth coordination between threads.
40. Write a program to find the longest increasing subsequence (LIS) in an array.
Answer:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int longestIncreasingSubsequence(vector<int> &nums) {
vector<int> lis;
for (int num : nums) {
auto pos = lower_bound(lis.begin(), lis.end(), num);
if (pos == lis.end()) lis.push_back(num);
else *pos = num;
}
return lis.size();
}
int main() {
vector<int> nums = {10, 9, 2, 5, 3, 7, 101, 18};
cout << "Length of LIS: " << longestIncreasingSubsequence(nums); // Output: 4
}
41. Write a program to reverse a linked list.
Answer:
#include <iostream>
using namespace std;
struct Node {
int data;
Node* next;
Node(int val) : data(val), next(nullptr) {}
};
Node* reverse(Node* head) {
Node *prev = nullptr, *current = head, *next = nullptr;
while (current) {
next = current->next;
current->next = prev;
prev = current;
current = next;
}
return prev;
}
void printList(Node* head) {
while (head) {
cout << head->data << " ";
head = head->next;
}
}
int main() {
Node* head = new Node(1);
head->next = new Node(2);
head->next->next = new Node(3);
head = reverse(head);
printList(head); // Output: 3 2 1
}
42. Write a program to find the Kth largest element in an array.
Answer:
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int findKthLargest(vector<int>& nums, int k) {
priority_queue<int, vector<int>, greater<int>> minHeap;
for (int num : nums) {
minHeap.push(num);
if (minHeap.size() > k) minHeap.pop();
}
return minHeap.top();
}
int main() {
vector<int> nums = {3, 2, 1, 5, 6, 4};
int k = 2;
cout << "Kth Largest: " << findKthLargest(nums, k); // Output: 5
}
Concluding Thoughts…
C++ has stood the test of time as one of the most versatile and efficient programming languages. From understanding foundational concepts like pointers and memory management to tackling advanced topics like multithreading and design patterns, this list of C++ Interview Questions and Answers provides a comprehensive roadmap to elevate your preparation.
By mastering these questions, you not only sharpen your technical skills but also demonstrate your ability to solve real-world problems effectively. If you have any doubts about any of these questions or the article itself, reach out to me in the comments section below.
Did you enjoy this article?