Top 17 C++ Backend Interview Questions with Answers and Code Samples
This article compiles 17 common C++ backend interview questions covering algorithms, data structures, language nuances, Linux process handling, SQL, networking, and system design, providing concise explanations and complete code examples to help candidates prepare effectively.
Non‑recursive binary search
A classic implementation uses three integer variables: low (initially 0), high (initially len‑1) and mid. In a while (low <= high) loop the middle index is computed as (low + high) / 2. If array[mid] equals the target, the index is returned. If the target is larger, low is moved to mid + 1; otherwise high becomes mid - 1. When the loop exits the value is not present and -1 is returned.
int binarySearch(int* array, int len, int value) {
int low = 0, high = len - 1;
while (low <= high) {
int mid = (low + high) / 2;
if (array[mid] == value) return mid;
if (value > array[mid]) low = mid + 1;
else high = mid - 1;
}
return -1;
}Finding the second largest element in an array (O(n))
The optimal linear‑time solution scans the array once while maintaining two variables: max (largest seen so far) and secondMax (second largest). The algorithm initializes these two with the first two elements (ordering them appropriately) and then processes each remaining element v as follows:
If v is greater than max, assign secondMax = max and max = v.
Else if v is greater than secondMax, assign secondMax = v.
After the loop, secondMax holds the required value (or -1 if the array length is ≤ 1).
int getSecondMax(int array[], int len) {
if (len <= 1) return -1;
int max, secondMax;
if (array[0] > array[1]) { max = array[0]; secondMax = array[1]; }
else { max = array[1]; secondMax = array[0]; }
for (int i = 2; i < len; ++i) {
int v = array[i];
if (v > max) { secondMax = max; max = v; }
else if (v > secondMax) { secondMax = v; }
}
return secondMax;
}Differences between struct and class in C++
Default member access: struct members are public by default; class members are private.
Default inheritance access: base‑class inheritance is public for struct, private for class.
Aggregate initialization: a struct without user‑defined constructors can be initialized with brace syntax (e.g., MyStruct s{1, 2};). A class can be aggregate‑initialized only if it meets the same criteria (no constructors, no private/protected non‑static data members, etc.).
Template parameter keyword: both class and typename are allowed; struct cannot be used as a template‑parameter keyword.
Implementation of polymorphism in C++
Polymorphism is realized through a hidden virtual‑function table (v‑table). Each class that declares or inherits virtual functions gets a static v‑table containing pointers to the most‑derived overrides. Every object of such a class stores a hidden pointer (often called the v‑ptr) to its class’s v‑table. At run time, a call to a virtual function is dispatched by looking up the function pointer in the object’s v‑table, enabling dynamic binding.
Role of the static keyword in C
When applied to a variable at file scope, it gives the variable internal linkage (visible only within the translation unit) and static storage duration (lifetime for the entire program).
When applied to a function, it restricts the function’s linkage to the defining translation unit, preventing external references.
When used inside a function, a static local variable retains its value between calls.
Role of the extern keyword in C
externdeclares a variable or function without defining it, indicating that its definition resides in another translation unit. This allows the compiler to resolve references across multiple source files.
Purpose of extern "C" in C++
It forces C linkage for the declared function(s), disabling C++ name mangling. This makes the symbols compatible with C object files, enabling mixed C/C++ linking.
C/C++ program memory layout
The typical layout (from low to high addresses) is:
Text segment : executable code.
Data segment : initialized global/static variables.
BSS segment : uninitialized global/static variables (zero‑filled).
Heap : dynamically allocated memory (via malloc, new).
Stack : function call frames, local variables, return addresses.
An illustrative diagram:
Zombie processes
A zombie occurs when a child process terminates but its parent does not invoke wait or waitpid to reap the exit status. The kernel retains a minimal task structure for the child, marked as Z, until the parent collects the status.
Preventing zombies
Parent explicitly calls wait / waitpid after forking.
Install a SIGCHLD handler that calls wait when the signal is delivered.
Ignore SIGCHLD with signal(SIGCHLD, SIG_IGN); the kernel automatically reaps the child.
Double‑fork: the intermediate child exits, leaving the grandchild adopted by init, which will reap it when it terminates.
Macro to compute array length
#define ARRAY_LEN(arr) (sizeof(arr) / sizeof((arr)[0]))Removing duplicate lines from a text file in Linux
Common one‑liner pipelines (assuming the file is unsorted): sort -u file – sorts and removes duplicates in a single step. sort file | uniq – sorts then filters adjacent duplicates. sort file | awk '{if ($0 != prev) print; prev=$0}' – uses awk to print only lines that differ from the previous line.
sort file | sed '$!N; /^
\\1$/!P;D'– uses sed to delete adjacent duplicate lines.
epoll and its purpose
epollis a Linux kernel I/O multiplexing API designed for high‑performance handling of large numbers of file descriptors. It avoids the O(n) scanning overhead of select / poll by maintaining a ready‑list of active descriptors, reducing CPU usage when most descriptors are idle.
Advantages of epoll over select
Supports both level‑triggered (LT) and edge‑triggered (ET) event notification.
No hard limit on the number of monitored descriptors (select is limited by FD_SETSIZE, typically 1024).
Performance remains roughly constant as the number of watched descriptors grows, because epoll does not iterate over all descriptors.
Uses a shared memory region (via mmap) for kernel‑user communication, reducing data copies.
Creating an epoll instance: int epfd = epoll_create1(0); (the size argument in older epoll_create is only a hint). The returned file descriptor must be closed with close(epfd) when no longer needed.
SQL query for the top three most frequent ages
SELECT TOP 3 Age, cnt FROM (
SELECT Age, COUNT(*) AS cnt
FROM table1
GROUP BY Age
) AS sub
ORDER BY cnt DESC;Five‑layer network protocol model
The model (similar to OSI) consists of:
Physical layer
Data link layer
Network layer
Transport layer
Application layer
An illustrative diagram is shown below.
Design considerations for massive concurrent QQ logins
Transport protocol : Choose TCP with keep‑alive or a lightweight custom protocol to maintain persistent connections.
Load balancing : Deploy hardware or software load balancers (e.g., LVS, Nginx) to distribute incoming connections across a pool of application servers.
Concurrency model : Use asynchronous I/O (epoll, io_uring) or event‑driven frameworks; if threading is preferred, employ a thread pool with connection pooling to limit context‑switch overhead.
Resource optimization : Apply connection reuse, back‑pressure handling, and efficient serialization/deserialization to reduce per‑connection CPU and memory footprints.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ITPUB
Official ITPUB account sharing technical insights, community news, and exciting events.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
