C++ is a powerful, structured, and object-oriented language used extensively in systems programming, game development, competitive coding, and more. If you’re preparing for a C++ interview, mastering the fundamentals is critical. This article breaks down the core topics interviewers frequently ask about, along with relevant sample questions.
It suitable for both freshers and those brushing up their base concepts for technical interviews.
1. How does C++ enable both high-level and low-level programming, and what features make it suitable for systems-level development?
Explanation:
C++ is often referred to as a mid-level language because it bridges the gap between:
- High-level features (like classes, inheritance, templates)
- Low-level access (like pointer arithmetic, inline assembly)
This allows C++ to be used for both abstraction-heavy application development and performance-critical system programming (like OS kernels, device drivers).
C++
#include <iostream>
using namespace std;
class Device {
public:
int *ptr;
Device() {
ptr = new int(10); // dynamic memory (low-level)
}
~Device() {
delete ptr;
}
void show() {
cout << "Value in device: " << *ptr << endl;
}
};
int main() {
Device d;
d.show();
return 0;
}
2. How does type deduction using auto
and decltype
in C++ enhance type safety and flexibility? Show how these modern features relate to built-in and user-defined data types.
Explanation: Instead of manually specifying data types, C++ allows the compiler to deduce the type using:
auto
: Deduces the type from initializer.decltype
: Infers type from an expression.
These features:
- Reduce boilerplate.
- Improve maintainability.
- Prevent type mismatches.
Code:
C++
#include <iostream>
using namespace std;
int getNumber() { return 42; }
int main() {
auto x = 10.5; // deduced as double
decltype(getNumber()) y = 5; // deduced as int (from return type)
cout << "x: " << x << ", y: " << y << endl;
return 0;
}
3. Define 'std'?
'std' is also known as Standard or it can be interpreted as a namespace. The command "using namespace std" informs the compiler to add everything under the std namespace and inculcate them in the global namespace. This all inculcation of global namespace benefits us to use "cout" and "cin" without using "std::_operator_".
C++
#include <iostream>
using namespace std;
int main() {
cout << "Hello using std namespace!" << endl;
return 0;
}
4. What are references in C++?
In C++, references are an alternative way to create an alias for another variable. A reference acts as a synonym for a variable, allowing you to access the variable directly without any additional syntax. They must be initialized when created and cannot be changed to refer to another variable afterward. This feature makes it easier to manipulate variables in functions while avoiding the overhead of copying large objects. A reference variable is preceded with a '&' symbol.
Syntax:
int GFG = 10;
// reference variable
int& ref = GFG;
C++
#include <iostream>
using namespace std;
int main() {
int a = 10;
int &ref = a;
ref = 20;
cout << "a = " << a << ", ref = " << ref << endl;
return 0;
}
5. What do you mean by Call by Value and Call by Reference?
In this programming language to call a function we have 2 methods: Call by Value and Call by Reference
Call by Value | Call by Reference |
---|
A copy of a variable is passed. | A variable itself is passed fundamentally. |
Calling a function by sending the values by copying variables. | Calling a function by sending the address of the passed variable. |
The changes made in the function are never reflected outside the function on the variable. In short, the original value is never altered in Call by Value. | The changes made in the functions can be seen outside the function on the passed function. In short, the original value is altered in Call by reference. |
Passed actual and formal parameters are stored in different memory locations. Therefore, making Call by Value a little memory inefficient. | Passed actual and formal parameters are stored in the same memory location. Therefore, making Call by Reference a little more memory efficient. |
Call by Value:
C++
#include <iostream>
using namespace std;
void modify(int x) {
x = x + 10;
}
int main() {
int a = 5;
modify(a);
cout << "Value after call by value: " << a << endl;
return 0;
}
Call by Reference:
C++
#include <iostream>
using namespace std;
void modify(int &x) {
x = x + 10;
}
int main() {
int a = 5;
modify(a);
cout << "Value after call by reference: " << a << endl;
return 0;
}
6. Define token in C++
A token is the smallest individual element of a program that is understood by a compiler. A token comprises the following:
- Keywords: That contain a special meaning to the compiler
- Identifiers: That hold a unique value/identity
- Constants: That never change their value throughout the program
- Strings: That contains the homogenous sequence of data
- Special Symbols: They have some special meaning and cannot be used for another purpose; eg: [] () {}, ; * = #
- Operators: Who perform operations on the operand
C++
#include <iostream>
using namespace std; // Keyword
int main() {
int age = 25; // int (keyword), age (identifier), 25 (constant)
cout << "Age: " << age << endl; // "Age:" (string), << (operator)
return 0; // return (keyword), 0 (constant)
}
7. What is the difference between C and C++?
The following table lists the major differences between C and C++:
C | C++ |
---|
It is a procedural programming language. In simple words, it does not support classes and objects | It is a mixture of both procedural and object-oriented programming languages. In simple words, it supports classes and objects. |
It does not support any OOPs concepts like polymorphism, data abstraction, encapsulation, classes, and objects. | It supports all concepts of data |
It does not support Function and Operator Overloading | It supports Function and Operator Overloading respectively |
It is a function-driven language | It is an object-driven language |
C Code (No OOP):
C
#include <stdio.h>
void greet() {
printf("Hello from C-style function!\n");
}
int main() {
greet();
return 0;
}
C++ Code with OOP:
C++
#include <iostream>
using namespace std;
class Greet {
public:
void sayHello() {
cout << "Hello from C++ class!" << endl;
}
};
int main() {
Greet g;
g.sayHello();
return 0;
}
8. What happens if you use cout without using namespace std or std::cout? Why is namespace resolution important in large C++ projects?
In C++, cout belongs to the std namespace. If you forget to use using namespace std; or std::cout, you'll get a compiler error. In large projects, polluting the global namespace can lead to naming collisions
C++
#include <iostream>
// using namespace std; // not used intentionally
int main() {
std::cout << "Using std::cout directly avoids namespace pollution\n";
return 0;
}
9. What is the difference between const and #define?
- const is a typed(some data type) constant and is evaluated at runtime.
- #define is a macro (preprocessor directive) replaced before compilation and has no data type.
- const int x = 10; // Type safe
- #define y 10 // No type checking
10. What are default arguments?
Default arguments are values that are used when a function is called without some parameters.
C++
#include <iostream>
using namespace std;
void greet(string name = "Guest") {
cout << "Hello " << name;
}
int main() {
greet();
return 0;
}
11. How do you free memory allocated with new
?
Use delete for single values, and delete[] for arrays:
C++
#include <iostream>
using namespace std;
int main() {
int* p = new int;
delete p;
int* arr = new int[10];
delete[] arr;
return 0;
}
12. Can a reference be reseated to another variable after initialization? What happens if you try to return a reference to a local variable?
Explanation:
- References cannot be reseated.
- Returning a reference to a local variable causes undefined behavior — you're returning a variable that no longer exists after function ends.
Code:
C++
#include <iostream>
using namespace std;
int& getLocal() {
int a = 10;
return a; // Returning reference to a local variable (UB)
}
int main() {
int &ref = getLocal();
cout << "Undefined behavior: " << ref << endl;
return 0;
}
13. Discuss the difference between prefix and postfix?
Following are the major difference between prefix and postfix:
prefix | postfix |
---|
It simply means putting the operator before the operand | It simply means putting the operator after the operand |
It executes itself before '; ' | It executes itself after '; ' |
Associativity of prefix ++ is right to left | Associativity of postfix ++ is left to right |
14. What is the difference between new and malloc()?
Following are the major difference between new and malloc()
new | malloc() |
---|
new is an operator which performs an operation | malloc is a function that returns and accepts values |
new calls the constructors | malloc cannot call a constructor |
new is faster than malloc as it is an operator | malloc is slower than new as it is a function |
new returns the exact data type | malloc returns void* |
15. Why might changes not reflect even when you think you're using call by reference?
Explanation: If you pass a pointer by value but forget to use dereferencing, changes won’t reflect.
Code:
C++
#include <iostream>
using namespace std;
void wrongUpdate(int *p) {
int x = 100;
p = &x; // Changing the pointer locally, not the original address
}
int main() {
int a = 10;
int *ptr = &a;
wrongUpdate(ptr);
cout << "Value: " << *ptr << endl; // Will still print 10
return 0;
}
16. How internally delete and delete[] works in cpp?
Purpose:
- delete and delete[] are used to deallocate memory that was previously allocated using new and new[], respectively.
- They free up heap memory to avoid memory leaks.
Memory Allocation: When you do new, the compiler:
- Allocates extra metadata (like size/type info) in memory (often before the actual object).
- Calls the constructor for the object(s).
- Returns a pointer to the allocated memory.
delete:
- Takes a pointer to a single object.
- Internally, Calls the destructor of the object.
- Passes the pointer to the heap deallocator (e.g., operator delete).
C++
ptr->~T(); // Call destructor
operator delete(ptr); // Free memory
delete[]:
- Takes a pointer to an array of objects.
- Internally, Retrieves the number of elements stored in metadata (hidden by the compiler).
- Calls the destructor for each element in reverse order.
- Calls operator delete[] to deallocate the memory block.
C++
for (int i = size - 1; i >= 0; --i)
arr[i].~T(); // Call destructor on each
operator delete[](arr); // Free memory
Note: If the object is a primitive type (int, char), destructors aren't needed.
17. In the line int* a, b;, how many pointers are declared?
Explanation: Many assume both a and b are pointers, but only a is a pointer — b is just an int.
Code:
C++
#include <iostream>
using namespace std;
int main() {
int* a, b; // a is a pointer, b is just an int
int x = 5;
a = &x;
cout << "Pointer a: " << *a << ", Integer b: " << b << endl;
return 0;
}
18. Define storage class in C++ and name some
Storage class is used to define the features(lifetime and visibility) of a variable or function. These features usually help in tracing the existence of a variable during the runtime of a program.
Syntax:
storage_class var_data_type var_name;
Some types of storage classes:
Examples of storage class19. What is a mutable storage class specifier? How can they be used?
The mutable keyword is a storage class specifier used only with non-static data members of a class. It allows a member of a const object to be modified. Normally, if an object is declared const, you cannot modify any of its members, but mutable makes an exception.
Key Points:
- Used only with non-static, non-const, and non-reference data members.
- Allows modification even inside: A const object & A const member function
- Useful in caching, lazy evaluation, logging, etc., where some internal state can change without affecting observable behavior.
Why is mutable Needed: When a member function is marked as const like this
void show() const;
It cannot modify any data members of the object, because this becomes a const pointer (i.e., const ClassName* this). But sometimes, you want to modify an internal variable (e.g., access counter, log flag) that is not part of the logical state of the object. That’s where mutable helps.
Example:
C++
#include <iostream>
using namespace std;
class Logger {
private:
mutable int accessCount; // can change even in const functions
string data;
public:
Logger(string d) : data(d), accessCount(0) {}
void showData() const {
accessCount++; // allowed because accessCount is mutable
cout << "Data: " << data << ", Accessed: " << accessCount << " times\n";
}
};
int main() {
const Logger log("Secret Info");
log.showData(); // Allowed even though log is const
log.showData(); // Internal counter keeps updating
}
Even though log
is declared as const
, accessCount
is being updated, because it is declared mutable
.
20. Define the Block scope variable.
A block scope variable is also known as a local scope variable. A variable that is defined inside a function (like main) or inside a block (like loops and if blocks) is a local variable. It can be used ONLY inside that particular function/block in which it is declared. a block-scoped variable will not be available outside the block even if the block is inside a function.
C++
#include <iostream>
using namespace std;
int main() {
int a = 10; // local to main
if (a > 5) {
int b = 20; // block scope inside if-block
cout << "Inside if-block: a = " << a << ", b = " << b << endl;
}
for (int i = 0; i < 3; i++) {
int temp = i * 10; // block scope inside for-loop
cout << "temp = " << temp << endl;
}
return 0;
}
21. What is the function of the keyword "Auto"?
The auto keyword is a type inference specifier introduced in C++11, which tells the compiler to automatically deduce the type of a variable from its initializer expression.
Primary Function of auto:
- Simplifies declarations (especially for iterators, lambdas, template types).
- Enhances code readability and maintainability.
- Reduces redundancy and typing errors.
- Promotes use of generic programming.
Use Case: With Iterators use this
C++
#include <bits/stdc++.h>
using namespace std;
int main() {
vector<int> v = {1, 2, 3, 4};
for (auto it = v.begin(); it != v.end(); ++it)
cout << *it << " ";
return 0;
}
Instead of this:
std::vector<int>::iterator it = v.begin();
22. Define namespace in C++.
Namespaces enable us to organize named items that would otherwise have global scope into smaller scopes, allowing us to give them namespace scope. This permits program parts to be organized into distinct logical scopes with names. The namespace provides a place to define or declare identifiers such as variables, methods, and classes.
Or we could say that A namespace is a declarative zone that gives the identifiers (names of types, functions, variables, and so on) within it a scope. Namespaces are used to arrange code into logical categories and to avoid name clashes, which might happen when you have many libraries in your code base.
C++
#include <iostream>
using namespace std;
// Define a namespace called "MathOps"
namespace MathOps {
int add(int a, int b) {
return a + b;
}
int multiply(int a, int b) {
return a * b;
}
}
int main() {
int x = 5, y = 3;
// Access functions using namespace scope resolution
cout << "Addition: " << MathOps::add(x, y) << endl;
cout << "Multiplication: " << MathOps::multiply(x, y) << endl;
return 0;
}
23. When is void() return type used?
The void keyword, when used as a function return type, indicates that the function does not return a value. When used as a parameter list for a function, void indicates that the function takes no parameters. Non-Value Returning functions are also known as void functions. They're called "void" since they're not designed to return anything. True, but only partially. We can't return values from void functions, but we can certainly return something. Although void functions have no return type, they can return values.
C++
#include <iostream>
using namespace std;
void greet() {
cout << "Hello from a void function!\n";
return; // valid, though it returns nothing
}
int main() {
greet();
return 0;
}
24. What is the difference between a reference and a pointer?
- Reference is an alias for a variable. It cannot be NULL and must be initialized.
- Pointer is a variable storing address. It can be reassigned and can be NULL.
C++
#include <iostream>
using namespace std;
int main() {
int a = 10;
int& ref = a; // reference
int* ptr = &a; // pointer
cout << "ref: " << ref << endl;
cout << "ptr: " << *ptr << endl;
*ptr = 20;
cout << "After changing via pointer, a = " << a << endl;
ref = 30;
cout << "After changing via reference, a = " << a << endl;
return 0;
}
25. What are type modifiers in C++?
Modifiers like signed, unsigned, long, short change the size or sign of basic data types.
Example:
unsigned int a = 5;
long double b = 5.66;
C++
#include <iostream>
using namespace std;
int main() {
unsigned int u = 10;
signed int s = -20;
short sh = 30000;
long lg = 100000L;
long long ll = 9223372036854775807LL;
cout << "unsigned int: " << u << endl;
cout << "signed int: " << s << endl;
cout << "short: " << sh << endl;
cout << "long: " << lg << endl;
cout << "long long: " << ll << endl;
return 0;
}
26. How we can make custom delete?
You can overload operator delete or operator delete[] in your class:
C++
void operator delete(void* ptr) {
std::cout << "Custom delete\n";
::operator delete(ptr);
}