C++ is a general purpose programming language that was developed in 1979 by Bjarne Stroustrup. C++ was born as an object-oriented superset of C. According to the Stack Overflow Developer Survey, C++ is one of the top six most popular programming languages. It is primarily used as an object-oriented programming (OOP) language.
Some C++ characteristics:
Object-oriented programming is a programming paradigm that organizes programs around objects, where each object may contain data and relevant functions. The person responsible for coining the term “object-oriented programming,” Alan Kay, stresses the importance of messaging for communication between objects.
That said, the relationship between objects is the foundation of object-oriented programming.
The four pillars of OOP are:
Abstraction: Abstraction refers to the ability of a class to hide its internal implementation details and expose only its essential features to the outside world. This allows users of an object of that class to interact with it without needing to know its internal workings.
Encapsulation: Encapsulation refers to the idea of keeping the internal state (i.e. current values of attributes) and behavior of an object hidden from the outside world while providing a public interface for interacting with it. This allows the class or object to control access to its internal data and behavior, and protect it from being modified or accessed in an unintended way.
Inheritance: Two classes (say Car
, and Toyota
) have the inheritance relationship between them when one class, say Toyota
, is extending the other class (Car
). In this example, Car
will be referred to as a base-class or a superclass whereas Toyota
will be referred to as a derived-class or subclass. Inheritance allows a derived class to take some of the attributes and methods of the base class. Moreover, the derived class may enhance the base class by introducing additional attributes and methods. Inheritance promotes code reusability and extensibility.
Polymorphism: Polymorphism allows objects of different classes to be treated as objects of one of their common superclasses. This enables methods to be defined on the superclass to be overridden by subclasses to provide their own implementation. Thus a single method call can be executed on objects of multiple classes, with the appropriate implementation being called based on the actual class of the object.
Abstraction vs. Encapsulation: The difference between abstraction and encapsulation is commonly misunderstood. Abstraction is about hiding complexity and only showing the essential features, while encapsulation is about protecting the internal state and behavior of an object and controlling access to it.
It’s no secret you have to practice, but five out of six interviewers will fail a coding interview. So, how do you practice effectively? There are two main schools of thought when it comes to coding interview prep:
Pattern-based approach: Learn a total of 24 patterns that teach how to recognize, diagnose, and solve any interview question you may be presented with.
Get hands-on with C++ today
With thousands of potential questions to account for, preparing for the coding interview can feel like an impossible challenge. Yet with a strategic approach, coding interview prep doesn’t have to take more than a few weeks. Stop drilling endless sets of practice problems, and prepare more efficiently by learning coding interview patterns. This course teaches you the underlying patterns behind common coding interview questions. By learning these essential patterns, you will be able to unpack and answer any problem the right way — just by assessing the problem statement. This approach was created by FAANG hiring managers to help you prepare for the typical rounds of interviews at major tech companies like Apple, Google, Meta, Microsoft, and Amazon. Before long, you will have the skills you need to unlock even the most challenging questions, grok the coding interview, and level up your career with confidence. This course is also available in JavaScript, Python, Go, and C++ — with more coming soon!
Below is a list of questions we have compiled not to represent the popular C++ questions that are asked by interviewers, but to give you an idea of the types of content you should be reviewing.
Note: We have only recorded one example answer, but there are multiple correct responses to most of these questions.
As mentioned above, C++ was developed as a superset of C. C++ was originally called “C with classes,” and the original goal was to create a version of C that facilitated an object-oriented model without compromising speed or low-level functionality. C++ is able to combine the procedural functionality of C with the flexibility and usability of OOP.
Classes and objects are not a feature of C++ in particular. They are integral to all object-oriented programming languages. A class is like a blueprint which does not exist during a program execution. However, based on a class design, at runtime, we can create its object(s). An object has the same attributes and methods which were defined in its class. Let’s see a simple example of creating a class and making its objects in C++:
Attribute vs. Variable: An attribute is a variable defined in a class.
#include <iostream>class Car {public:/*** The attributes of class Car.*/int number;int year;/** The methods of class Car.*/int getNumber() {return number;}int getYear() {return year;}void setNumber(int number) {this->number = number;}void setYear(int year) {this->year = year;}};int main() {/*** Creating object of the class Car*/Car myCar;// Using the car objectmyCar.setNumber(777);myCar.setYear(2018);//Printing its attributesstd::cout << "My car number and manufacturing year are: " << myCar.number << ", " << myCar.year << "\n";return 0;}
A constructor is a special function of a class which is called automatically upon creation of an object. Thus, a constructor usually outline the steps that occur when one instance of a class is created.
A constructor’s name must be the same as it’s class name.
Put simply, constructors can create and initialize objects of their class type. They cannot be classified as volatile
or static
nor can the body of a constructor contain a return statement.
The following code playground demonstrates the creation and use of a class’s constructors:
#include <iostream>class Car {public:/*** The attributes of class Car.*/int number;int year;/*** An empty constructor of the class Car*/Car() {std::cout << "Constructor-A is called\n";}/*** Another constructor of the class Car*/Car(int number, int year) {std::cout << "Constructor-B is called\n";this->number = number;this->year = year;}/** The methods of the class Car.*/int getNumber() {return number;}int getYear() {return year;}void setNumber(int number) {this->number = number;}void setYear(int year) {this->year = year;}};int main() {/*** Creating object of the class Car and using its constructor*/Car myCar(777, 2018);//Printing its attributesstd::cout << "My car number and manufacturing year are: " << myCar.number << ", " << myCar.year << "\n";return 0;}
Also called structs, structures serve as a way to group related variables together. Each variable is known as a member of the structure.
Structures are created with the struct
keyword and members are declared within curly braces.
C++ structure is very similar to class. However, a key difference is that class attributes are by default ‘private’ whereas struct
attributes are by default ‘public’. Thus, by default ‘struct’ attributes can be directly accessed and modified.
A pointer is a variable that stores the address of another variable. The this
pointer is only accessible in non-static member functions of classes, structs, or unions. It refers to the object on which the member function is called.
There are several use cases for the this
pointer.
this
pointer can be used to return the reference of the calling object.this
pointer can be used to distinguish between the two when assigning values.The this
pointer is always passed to the constructor as it holds the address to the object being constructed. If you’re interested, we have some example code on Educative Answers.
Access specifiers define how different variables and functions that are contained within a class can be accessed.
public
: A public attribute or function of a class can be accessed outside of that classprivate
: A private attribute or function of a class cannot be accessed outside of that classprotected
: A protected attribute or function of a class cannot be accessed outside of that class, except the subclasses of that class.A class can declare other classes as a friend, and as a result, a friend class can then access the private and protected members of that class. This is important as it facilitates encapsulation of the non-relevant elements of a data structure to the user, but extends the storage and access to component parts.
Friend functions are primarily important in expanding the functionality of data structures like linked lists. A linked list class may be declared as a friend to access private members of a node.
The four pillars of OOP, as discussed earlier in this article, are: abstraction, encapsulation, inheritance, and polymorphism.
Here we’ll cover the very basics of each pillar, but we recommend looking over the above section dedicated to OOP if you need a more thorough explanation.
Abstraction: Some of an object’s properties and methods are hidden from outside observation.
Encapsulation: Related variables and functions are grouped into objects based on a larger blueprint called a class.
Inheritance: Some of the properties and methods of one object may be passed down to another object.
Polymorphism: Literally “many forms,” polymorphism refers to objects that respond in different ways to the same function.
Function overloading or function overriding are examples of different kinds of polymorphism in C++ (see the question about compile-time and runtime polymorphism). Both serve as different ways to simplify the interface and make programs more intuitive to use and write. Function overloading and overriding are similar sounding terminologies, having vastly different characteristics. Therefore, this question is frequently being asked in coding interviews and is commonly answered incorrectly. Let’s understand it clearly with examples.
Overloading refers to the functions of the same scope (such as a class scope or the global scope) having the same name but different parameters. For example, in the code below we have two functions defined in global scope where both functions have the same name printMulti
but different parameters.
#include <iostream>void printMulti(int x, int y) {std::cout << x * y << std::endl;}void printMulti(double x, double y) {std::cout << x * y << std::endl;}int main() {printMulti(3, 5); // Automatically calls the first functionprintMulti(3.1, 5.2); // Selects to calls the second functionreturn 0;}
Overriding When a superclass function is rewritten (with exactly the same name, parameters, and return type) in a subclass but having different implementation, we refer to the subclass function overriding the superclass function and this technique is referred to as function overriding. A same function may be overridden multiple times in different subclasses. In the example below we have the Shape
superclass and its two subclasses Rectangle
and Circle
. A function calc_circumference
is virtual in the superclass but have different implementations in the subclasses.
#include <iostream>class Shape {public:virtual double calc_circumference() = 0;};class Rectangle : public Shape {private:double width;double height;public:Rectangle(double w, double h) {width = w;height = h;}//Overriding function of the base classvirtual double calc_circumference() {return 2*width*height;}};class Circle : public Shape {private:double radius;public:Circle(double r) {radius = r;}//Overriding function of the base classvirtual double calc_circumference() {return 2*3.14*radius;}};int main() {int width = 3, height = 4;double radius = 3;//Ah! This is polymorphism where Shape objects could be of either type: Rectangle and Circle.// The function being called depends on the object initiation.Shape *shape1 = new Rectangle(width, height);Shape *shape2 = new Circle(radius);std::cout << "Rectangle with width="<<width<<", height= "<< height << " has area="<<shape1->calc_circumference()<< std::endl; // calls the Rectangle's implementationstd::cout << "Circle with radius="<<radius<< " has area="<<shape2->calc_circumference() << std::endl; // calls the Circle's implementation//Do not forget to free the memorydelete shape1;delete shape2;return 0;}
In C++, polymorphism refers to the ability of objects of different classes to respond to the same method call in different ways. There are two main types of polymorphism in C++: compile-time polymorphism and runtime polymorphism.
Compile-time polymorphism, also known as static polymorphism, is implemented through function overloading and operator overloading. Function overloading allows multiple functions with the same name but different parameter lists to be defined in the same scope.
Runtime polymorphism, also known as dynamic polymorphism, is implemented through inheritance and virtual functions. Inheritance allows classes to inherit properties and behaviors from their base classes. Virtual functions allow derived classes to override the implementation of a base class method so that objects of the derived class can respond to the same method call in different ways. The actual implementation of a virtual function is determined at runtime based on the actual type of the object, not just the declared type.
The new
operator is used for dynamic memory allocation. The operator denotes a request for allocating memory to the Heap. If the memory is available it is initialized and then the pointer to the newly allocated memory is returned. The code below creates an array dynamically based on the input size which could be taken at runtime from a user.
#include <iostream>int main() {//The size value can be decided at runtime via a user's inputint size = 10;//The array is created at the runtime (a.k.a dynamic memory allocation).int *array = new int[size];std::cout<<"Address of dynamically created array = "<<(void *)array << "\n";return 0;}
The scope of a variable relates to the block of code the variable is contained within. Where, the block may refer to a function, program, loop, or any code placed between opening and closing curly braces. There are two main designations when it comes to the scope of a given variable:
The following code playground demonstrates local scope to a function and an if-block. Moreover, it also shows a variable with the global scope.
#include <iostream>//g_x is a global variableint g_x = 10;int foo(int ilocal) {//ilocal and jlocal both are local variables to the foo functionint jlocal = 5;if (ilocal < 5) {// the scope of flocal is this if-blockint flocal = 10;ilocal = flocal;}std::cout << "We cannot access flocal outside the above if-block" << '\n';return jlocal+ilocal;}int main() {int llocal = foo(20);std::cout << "We cannot access ilocal and jlocal outside the foo function" << '\n';// But we can access the global variable g_x herestd::cout << "Value of global variable is=" << g_x << '\n';//We can access llocal here as it scope is the current functionstd::cout << "Value of local variable to main() is=" << llocal;return 0;}
If both variables are present in the same function, the local variable takes precedence over a global variable. Outside of the function, the local variable goes out of scope and the global variable remains available to use.
Recursion is a technique in which a function calls itself, either directly or via other functions. A function that employs recursion is called a recursive function. Although every recursive function can always be converted into an iterative (non-recursive) function, recursion is usually preferred as it significantly shortens the length of code and makes it simple to understand.
In contrast, it is recommended not to use recursion on the embedded, resource-constrained devices as each recursive call needs additional call-stack memory. Thus, a recursive function is usually slower and more memory-consuming compared to its iterative counterpart.
Let’s admire the simplicity of a recursive function that returns the nth Fibonacci number:
#include <iostream>/*** Returns the nth fibonacci number*/int fibonacci(int n){int fib;if (n <= 1){fib = n;} else {fib = fibonacci(n-1) + fibonacci(n-2);}return fib;}int main(){std::cout<<"The 6th fibonacci number is = "<<fibonacci(6)<<"\n";return 0;}
The basic logic is as follows:
#include <iostream>/*** Returns the minimum element of the input array.*/int findMin(int array[], int size) {int min = array[0];for (int curIndex=0; curIndex<size; curIndex++) {if (array[curIndex] < min) {min = array[curIndex];}}return min;}int main() {int array[9] = {5, 6, 7, -2, 0, -3, -1, -5, 1};std::cout<<"Minimum element of the array is = "<<findMin(array, 9)<<"\n";return 0;}
The scope resolution operator looks like this: ::
. In programming we use the word “scope” to refer to the code block in which certain functions and variables can be accessed. The scope resolution operator allows a member variable and a derived class type to have the same name. The ::
operator resolves any ambiguity when the code reaches the compiler. According to the operator, whatever comes before it is a typename, namespace, or global namespace.
As opposed to the
.
operator which communicates whatever comes before it as an object.
Basic arrays are one dimensional lists of data, but any data tables that we are familiar with require two dimensions. An Excel table is an example of a two dimensional array.
The syntax to declare a two dimensional array looks like this:
data_type
array_name
[dimension1]
[dimension2]
data_type
: the type of data to be stored in the array
array_name
: what the array will be named/stored as
[dimensionN]
: The sizes of each dimension of the array
By following the syntax, we can also create an array of higher than two dimensions.
Formal parameters are the variables that receive values when the function is called. Actual parameters are the values that are passed to the function when it is called.
In the example below variables x
and y
are the formal parameters of function printSum
whereas, 3
and 5
are the actual parameters that are passed to that function.
#include <iostream>//x and y are formal parametersvoid printSum(int x, int y) {std::cout << x + y << std::endl;}int main() {printSum(3, 5); // actual parameters: 3 and 5return 0;}
Once declared, constant variables in C++ cannot be changed. If you try to overwrite the value of a const
nothing will change and the compiler will give an error message. One way to overwrite the value of a constant after it is declared is to use the const_cast
operator. There are other potential methods for overwriting the values of const
variables, but they are usually not recommended.
const int constant_value = 10;int main() {constant_value = 20; // This will result in a compiler errorreturn 0;}
There are many different ways to swap the values of two variables in C++. The most common are probably to use a third variable or to use the swap()
function.
Below is example code showcasing the syntax of the swap()
function.
#include <bits/stdc++.h>using namespace std;int main(){int x = 12, y = 24;cout << "The value of x before: " << x << "\n";cout << "The value of y before: " << y << "\n";swap(x,y);//this function swaps the values of x and y and returns nothingcout << "The value of x now: " << x << "\n";cout << "The value of y now: " << y << "\n";return 0;}
Get hands-on with C++ today
With thousands of potential questions to account for, preparing for the coding interview can feel like an impossible challenge. Yet with a strategic approach, coding interview prep doesn’t have to take more than a few weeks. Stop drilling endless sets of practice problems, and prepare more efficiently by learning coding interview patterns. This course teaches you the underlying patterns behind common coding interview questions. By learning these essential patterns, you will be able to unpack and answer any problem the right way — just by assessing the problem statement. This approach was created by FAANG hiring managers to help you prepare for the typical rounds of interviews at major tech companies like Apple, Google, Meta, Microsoft, and Amazon. Before long, you will have the skills you need to unlock even the most challenging questions, grok the coding interview, and level up your career with confidence. This course is also available in JavaScript, Python, Go, and C++ — with more coming soon!
Hopefully you got some use out of these C++ questions and answers. It’s crucial that you test yourself when preparing for an interview. That said, spending a lot of time studying and attempting practice questions isn’t the most efficient way to prep. Almost every single technical interview asks questions that are built on larger coding interview patterns. Educative offers courses for learning 24 of the most common interview patterns in five top languages. Check out our series on Grokking Coding Interview Patterns and nail your next technical interview.
Happy learning!
Free Resources