C++ references and const interview questions, with answers
References and const are where C++ first parts company with C, and interviewers use them to check that you know what a function really receives and what it is allowed to change. The questions are about what a reference is underneath, when to pass by value, by reference or by const reference, what happens when a reference outlives its object, and what each const in a declaration protects. Every answer below comes with code that was compiled and run.
The questions start with references themselves, move to how they are passed and returned, and end with const, constexpr and the cast that removes const. Then take the free C++ diagnostic — ten questions across every C++ topic in the bank — to see which of these you can explain but not yet predict.
The questions, with answers
1.What is a reference in C++, and how is it different from a pointer?
In short: A reference is another name for an existing object: it must be initialised, can never be re-bound or null, and is used without * or ->, while a pointer is a separate object holding an address.
Declaring int& r = n; makes r an alias for n: every use of r is a use of n, so incrementing r increments n, as below. A reference must be initialised when it is declared, it always refers to the same object afterwards, and there is no null reference, which is what makes a reference parameter a promise that an object exists. A pointer is an object in its own right: it can be null, can be re-pointed, has its own address, and needs * or -> to reach the target. Compilers usually implement a reference as a hidden pointer, but the language treats it as the object itself, so sizeof(r) is the size of n, and &r is the address of n.
int n = 4; int& r = n; r += 3; std::cout << n << " "; std::cout << (&r == &n); // 7 1
2.When should a C++ function take its parameter by value, by reference, or by const reference?
In short: Take small, cheap-to-copy types by value, take an object you must modify by non-const reference, and take a large object you only read by const reference.
Passing by value copies the argument, which is ideal for built-in types, small structs and anything the function would copy anyway, since the copy can then be moved from. Passing by non-const reference, T&, lets the function modify the caller's object, and it signals that intent at the declaration. Passing by const reference, const T&, avoids the copy of a large object such as a string or vector while promising not to change it, and a const reference can bind to a temporary, which a plain T& cannot, so it accepts literals and expressions too, as below. A common modern choice for read-only strings is std::string_view, which is passed by value and accepts a string, a literal or a substring without copying.
using Nums = std::vector<int>; int total(const Nums& v) { int s = 0; for (int x : v) s += x; return s; } int main() { int t = total({1, 2, 3}); std::cout << t; } // 6
3.Can a C++ function return a reference, and when is that dangerous?
In short: Yes, and it lets a call be used as an lvalue, but returning a reference to a local variable or a temporary leaves a dangling reference, which is undefined behaviour.
Returning T& is safe when the object outlives the call: a member of *this, an element of a container the caller owns, or an object passed in by reference. It is how operator[] lets you write v[2] = 9 and how method chaining returns *this. It is dangerous when the object dies at the end of the function: a local variable, or a temporary created inside the function, leaves the caller holding a reference to destroyed storage, which is undefined behaviour, although g++ warns that the function returns a reference to a local. When in doubt, return by value; the move or copy elision makes it cheap.
int& at(std::vector<int>& v, int i) { return v[i]; } int main() { std::vector<int> v{5, 6}; at(v, 1) = 42; std::cout << v[1]; } // 42
4.What does const correctness mean in C++?
In short: Marking with const everything that should not change, parameters, member functions, pointers and return values, so the compiler enforces it and const objects stay usable.
const correctness is a habit, not a single rule: every parameter taken by reference that the function does not modify is const T&, every member function that does not modify the object is marked const after its parameter list, and pointers say whether the pointer, the pointee or both are fixed. The payoff is that the compiler rejects accidental writes, and that const objects and const references remain usable, because only const member functions may be called on them. It spreads: one missing const on a getter means a const reference to the class cannot call it, which is why it is easier to add const from the start than to retrofit it. const_cast can remove const, but writing through it to an object that was defined const is undefined behaviour.
class Temp { double c_ = 21.5; public: double c() const { return c_; } void set(double v) { c_ = v; } }; int main() { const Temp t; std::cout << t.c() << "\n"; } // 21.5
5.What is the difference between const and constexpr in C++?
In short: const means a value may not change after initialisation, which may happen at run time; constexpr means it is also known at compile time, so it can size arrays and be a template argument.
const int n = read(); is legal: n is fixed once initialised, but its value is only known at run time. constexpr int n = 8; requires a constant expression, so n can be used where the compiler needs a value, such as an array bound, a template argument or a case label. A constexpr function can be evaluated at compile time when its arguments are constant expressions and still runs normally at run time otherwise, as the example shows with a static_assert. C++20 adds consteval, for functions that must run at compile time, and constinit, for variables that must be initialised at compile time but may change later. constexpr on a variable implies const.
constexpr int sq(int x) { return x * x; } int main() { static_assert(sq(4) == 16); int arr[sq(3)]; std::cout << sizeof(arr); } // 36
6.What does const_cast do, and when is it legitimate?
In short: It adds or removes const or volatile on a reference or pointer; it is legitimate only when the object itself was not defined const, typically to call an old API that forgot a const.
const_cast is the only cast that can change constness. Its honest uses are narrow: calling a legacy C function declared with a char * parameter that you know does not write through it, or implementing the non-const overload of a member function in terms of its const twin to avoid duplicating code. Writing through the result is defined only if the object was not created const: removing const from a reference to an ordinary int and modifying it is fine, as below, but doing the same to a const int is undefined behaviour, because the compiler may have placed it in read-only memory or folded its value into the code. Needing const_cast anywhere else usually means a missing const in a declaration.
void legacy(char* s) { std::cout << s << "\n"; } int main() { std::string msg = "hello"; const std::string& r = msg; legacy(const_cast<char*>( r.c_str())); } // hello
How the diagnostic asks it
One question from the C++ bank, exactly as a sitting would show it. The bank has 3 on references & const and 30 across C++.
Which line of this C++ code does not compile?
int a = 1, b = 2; const int* p = &a; int* const q = &a; p = &b; *q = 5; *p = 3;
- 1*p = 3;correct
- 2p = &b;
- 3*q = 5;
- 4None: every line compiles
p is a pointer to a const int: p itself may be re-aimed, so p = &b is fine, but the int cannot be changed through it, so *p = 3 is rejected as an assignment of a read-only location. q is a const pointer to a modifiable int: it can never point anywhere else, but the int it points to can change, so *q = 5 is fine. None cannot be right, because *p = 3 writes through a pointer to const. The rule of thumb: const to the left of * protects the value, and const to the right of * protects the pointer, so q = &b would be the error for q.
Measure it
Reading answers tells you what’s true. A diagnostic tells you what you get wrong.
10 C++ questions across its topics, easy to hard, about fifteen minutes. You get a readiness figure with the arithmetic shown, the topics you missed named, and a practice set sized for today. Free: 1 diagnostic a month and 15 problems a day. No card.