upGrad KnowledgeHut SkillFest Sale!

C++ Interview Questions and Answers

C++ is a general-purpose, high-level programming language and an extension of the C programming language and provides additional features such as object-oriented programming, templates, and exceptions. C++ is widely used in various industries, including software development, gaming, finance, and scientific computing. Whether you’re preparing for your first C++ interview or for an advanced-level software interview, our wide variety of questions will help you prepare in the best way. The interview questions contain various topics like data types and operators, Exception handling in C++, object-oriented programming concepts, algorithms, and Debugging techniques and tools. By going through the C++ interview questions and answers, you can feel assured that you'll be thoroughly equipped for your upcoming interview.

  • 4.7 Rating
  • 30 Question(s)
  • 32 Mins of Read
  • 10716 Reader(s)

Beginner

One of the latest features of C++11 are a Move Constructor and a Move Assignment operator. We know that a Copy Constructor and a Copy Assignment is used to make a copy of one object to another, the Move Constructor and Move Assignment is to shift the ownership of the resources from one object to other. This is less expensive that object to object copy. A Move Constructor and Move Assignment operator is not provided by the compiler by default and one needs to implement the same.

Though both of them perform similar tasks, the differences between a Copy Constructor and an assignment operator is as follows:

  • While the former is an overloaded Constructor the latter is a Bitwise Operator.
  • The Copy Constructor can be used to initialize a new object with an existing object which is an overloaded Constructor while an assignment operator is invoked only when an object is being assigned to another object.
  • An assignment operator returns a value by default unlike a Copy Constructor. Both of them perform shallow copying by default. An overloaded assignment operator can be used to do deep copying.

Intermediate

This is a frequently asked question in c++ interview questions for freshers.

Stack Unwinding happens during exception handling. During an exception occurs, the destructor is called to destroy all local objects for the place where the exception was thrown and where it was caught. An exception causes the control to pass on from a try block to the respective exception handler.  The destructors for all constructed automatic objects are called at run time, which where created since the beginning of the try block. The automatic objects are destroyed in reverse order of their construction.

Note: The corresponding objects must be created before the destruction of the same, which takes place during Stack Unwinding.

The terminate() function is invoked during Stack Unwinding on a destructor for an unhandled exception.

The following example demonstrates this:

#include <iostream>
using namespace std;
struct E {
 const char* message;
 E(const char* arg) : message(arg) { }
};
void my_terminate() {
 cout << "Call to my_terminate" << endl;
};
struct A {
 A() { cout << "In constructor of A" << endl; }
 ~A() {
   cout << "In destructor of A" << endl;
   throw E("Exception thrown in ~A()");
 }
};
struct B {
 B() { cout << "In constructor of B" << endl; }
 ~B() { cout << "In destructor of B" << endl; }
};
int main() {
 set_terminate(my_terminate);
 try {
   cout << "In try block" << endl;
   A a;
   B b;
   throw("Exception thrown in try block of main()");
 }
 catch (const char* e) {
   cout << "Exception: " << e << endl;
 }
 catch (...) {
   cout << "Some exception caught in main()" << endl;
 }
 cout << "Resume execution of main()" << endl;
}

The output of this example:

In try block
In constructor of A
In constructor of B
In destructor of B
In destructor of A
Call to my_terminate

In the try block, two automatic objects are created: a and b. The try block throws an exception of type const char*. The handler catch (const char* e) catches this exception. The C++ run time unwinds the stack, calling the destructors for a and b in reverse order of their construction. The destructor for a throws an exception. Since there is no handler in the program that can handle this exception, the C++ run time calls terminate(). (The function terminate() calls the function specified as the argument to set_terminate(). In this example, terminate() has been specified to call my_terminate().)

Deep copy involves using the contents of one object to create another instance of the same class. In a deep copy, the two objects may contain ht same information but the target object will have its own buffers and resources. the destruction of either object will not affect the remaining object. The overloaded assignment operator would create a deep copy of objects.

Shallow copy involves copying the contents of one object into another instance of the same class thus creating a mirror image. Owing to straight copying of references and pointers, the two objects will share the same externally contained contents of the other object to be unpredictable.

Using a copy constructor we simply copy the data values member by member. This method of copying is called shallow copy. If the object is a simple class, comprised of built in types and no pointers this would be acceptable. This function would use the values and the objects and its behavior would not be altered with a shallow copy, only the addresses of pointers that are members are copied and not the value the address is pointing to. The data values of the object would then be inadvertently altered by the function. When the function goes out of scope, the copy of the object with all its data is popped off the stack.

If the object has any pointers a deep copy needs to be executed. With the deep copy of an object, memory is allocated for the object in free store and the elements pointed to are copied. A deep copy is used for objects that are returned from a function.

It's no surprise that this one pops up often in c++ interview questions and answers for freshers.

Name mangling is the process through which the C++ compilers give each function in the program a unique name. In C++, all programs have at least a few functions with the same name. Name mangling is a concession to the fact that linker always insists on all function names being unique. In C++, generally, programs have at least a few functions with the same name.

Example:

In general, member names are made unique by concatenating the name of the member with that of the class given the declaration:

class Bar

    {
           public:
               int ival;
               ...
     };

ival becomes something like:

     // a possible member name mangling
    ival__3Bar

Consider this derivation:

    class Foo : public Bar
   {
         public:
             int ival;
             ...
}

The internal representation of a Foo object is the concatenation of its base and derived class members.

    // Pseudo C++ code
   // Internal representation of Foo
   class Foo
   {
        public:
            int ival__3Bar;
            int ival__3Foo;
            ...
};

Unambiguous access of either ival members is achieved through name mangling. Member functions, because they can be overloaded, require an extensive mangling to provide each with a unique name. Here the compiler generates the same name for the two overloaded instances(Their argument lists make their instances unique).   

The main characteristics of static functions are as follows:

  • It is without the a “this” pointer. This is because it has no object address and hence “this” pointer is not passed as an internal parameter to the same. Also it can can be invoked even before creation of objects using scope resolution operator.
  • It can't directly access the non-static members of its class.
  • It can't be declared const, volatile or virtual.
  • It doesn't need to be invoked through an object of its class, although for convenience, it may.

An inline function is a request and not a command. Hence it won't be compiled as an inline function always.

Inline-expansion could fail if the inline function contains loops, the address of an inline function is used, or an inline function is called in a complex expression. The rules for in-lining are compiler dependent.

The scope resolution operator ‘::’ can be used to refer to members of the global namespace. Because the global namespace doesn’t have a name, the notation :: member-name refers to a member of the global namespace. This can be useful for referring to members of global namespace whose names have been hidden by names declared in nested local scope. Unless we specify to the compiler in which namespace to search for a declaration, the compiler simple searches the current scope, and any scopes in which the current scope is nested, to find the declaration for the name.

#include <iostream>
ostream& myhex ( ostream &o )
{
o.setf ( ios::hex) ;
return o ;
}
int main( )
{
cout << endl << myhex << 2000 ;
return 0;
}

Output:

 2000

A common question in C++ coding interview questions; don't miss this one.

There are two ways in which we can refer to the name of a class or function that is defined within a namespace: Using the scope resolution operator ‘::’ through the using keyword. This is shown in the following example:

There are two ways in which we can refer to a name of class or function that is defined within a namespace: Using scope resolution operator through the using keyword. This is shown in following example:
                             namespace name1
                             {
                             class sample1
                             {
                             // code
                             } ;
                             }
                            namespace name2
                             {
                             class sample2
                             {
                             // code
                             } ;
                             }
                             using namespace name2 ;
                             void main( )
                             {
                             name1::sample1 s1 ;
                             sample2 s2 ;
                             }

Here, class sample1 is referred using the scope resolution operator.

On the other hand we can directly refer to class sample2 because of the statement using namespace name2 ; the using keyword declares all the names in the namespace to be in the current scope. So we can use the names without any qualifiers.

Here, class sample1 is referred to using the scope resolution operator. On the other hand, we can directly refer to class sample2 because of the statement using namespace name2 ; the using keyword declares all the names in the namespace to be in the current scope. So we can use the names without any qualifiers.

No!. This is because even if we provide the default arguments to the parameters of the overloaded operator function we would end up using the binary operator incorrectly. This is explained in the following example:

                           sample operator + ( sample a, sample b = sample (2, 3.5f ) )
                           {
                           }
                            void main( )
                            {
                             sample s1, s2, s3 ;
                             s3 = s1 + ; // error
                             }

This concept is used to create a Singleton Class. Below is code snippet demonstrating the same: 

 
                             #include
                             class sample
                             {
                             static sample *ptr ;
                             private:
                             sample( )
                             {
                             }
                             public:
                             static sample* create( )
                             {
                             if ( ptr == NULL )
                             ptr = new sample ;
                             return ptr ;
                             }
                             } ;
                             sample *sample::ptr = NULL ;
                             void main( )
                             {
                             sample *a = sample::create( ) ;
                             sample *b = sample::create( ) ;
                             }


Here, the class sample contains a static data member ptr, which is a pointer to the object of same class. The constructor is private which avoids us from creating objects outside the class.  

A static member function called create( ) is used to create an object of the class. In this function the condition is checked whether or not ptr is NULL, if it is then an object is created dynamically and its address collected in ptr is returned. If ptr is not NULL, then the same address is returned. Thus, in main( ) on execution of the first statement one object of sample gets created whereas on execution of second statement, b holds the address of the first object. Thus, whatever number of times you call create( ) function, only one object of sample class will be available. 

    #include<iostream>

                             class date
                             {
                             private :
                             int day ;
                             int month ;
                             int year ;
                             public :
                             date ( int d = 0, int m = 0, int y = 0 )
                             {
                             day = d ;
                             month = m ;
                             year = y ;
                             }

                             // copy constructor
                             date ( date &d )
                             {
                             day = d.day ;
                             month = d.month ;
                             year = d.year ;  
                             }

                             // an overloaded assignment operator
                             date operator = ( date d )
                             {
                             day = d.day ;
                             month = d.month ;
                             year = d.year ;
                             return d ;  
                             }
                             void display( )
                             {
                             cout << day << "/" << month << "/" << year ;
                             }
                             } ;

                             void main( )
                             {
                             date d1 ( 25, 9, 1979 ) ;
                             date d2 = d1 ;
                             date d3 ;
                             d3 = d2 ;
                             d3.display( ) ;
                             }

While building an object of a derived class first the constructor of the base class and then the constructor of the derived class gets called. The object is said an immature object at the stage when the constructor of base class is called. This object will be called a matured object after the execution of the constructor of the derived class. Thus, if we call a virtual function when an object is still immature, obviously, the virtual function of the base class would get called. This is illustrated in the following example.

#include <iostream>

                             class base
                             {
                             protected :
                             int i ;
                             public :
                             base ( int ii = 0 )
                             {
                             i = ii ;
                             show( ) ;
                             }

                             virtual void show( )
                             {
                             cout << "base's show( )" << endl ;
                             }
                             } ;

                             class derived : public base
                             {
                             private :
                             int j ;
                             public :
                             derived ( int ii, int jj = 0 ) : base ( ii )
                             {
                             j = jj ;
                             show( ) ;
                             }
                             void show( )
                             {
                             cout << "derived's show( )" << endl ;
                             }
                             } ;
                               
                             void main( )
                             {
                             derived dobj ( 20, 5 ) ;
                             }

The output of this program would be:                         

base's show( )
derived's show( )

The following program demonstrates this.   

#include<iostream>
     void main( )
     {
     int i = 65000 ;

     int *iptr = reinterpret_cast ( i ) ;
     cout << endl << iptr ;

     iptr++ ;
     cout << endl << iptr ;

     i = reinterpret_cast ( iptr ) ;
     cout << endl << i ;

     i++ ;
     cout << endl << i ;
     }

Advanced

It's no surprise that this one pops up often in C++ interview questions for experienced.

Design Patterns are reusable solutions that can be applied to recurring Object Oriented Design problems. Singleton is one such design pattern that comes under the category of a Creational Design Pattern. It can be used to design such a class which can, at most have only a single instance at any point of time and cant be instantiated further. This concept can be applied for creation of a logger or hardware interface class which can have only one instance running at all times.

Example of Singleton class that is thread-safe:

In order to make the class thread safe, one needs to only create an instance when no other instance exists as below:

class Singleton
{
public:
static Singleton* getinstance();
   ...
private:
   static Singleton* volatile newinstance;
};
Singleton* Singleton::getinstance()
{
   if (newinstance == NULL)
{
      Guarder<Lock>lock(m_lock);
      if (newinstance == NULL)
{
         Singleton* volatile temp = static_cast< Singleton* >(operator  new (sizeof(Singleton)));
         Newinstance = temp;
       }
    }
   return newinstance;
}

Smart Pointers are used for better garbage collection so that there are no memory leaks. Using Smart Pointers, there is no need to call delete for any memory allocated dynamically and it gets automatically deallocated.

Smart Pointers Implementations can be found in C++11 and higher versions. C++11 libraries provide four kinds of Smart pointers namely: auto_ptr, unique_ptr, shared_ptr and weak_ptr.

The below example implements a generic smart pointer which can used for all datatypes:

#include<iostream>
using namespace std;
template <class T>
class SmartPtr
{
   T *ptr; 
public:
   // Constructor
   explicit SmartPtr(T *p = NULL) { ptr = p; }
   // Destructor
   ~SmartPtr() { delete(ptr); }
   // Overloading dereferncing operator
   T & operator * () {  return *ptr; }
   // Overloding arrow operator so that members of T can be accessed
   // like a pointer (useful if T represents a class or struct or 
   // union type)
   T * operator -> () { return ptr; }
};
int main()
{
    SmartPtr<int> ptr(new int());
    *ptr = 20;
    cout << *ptr;
    return 0;
}

Vectors and Lists are defined under C++ Standard Template Library (STL). These data structures are basically sequential containers implemented using STLs.

The differences between them are as follows:

  • A Vector is a contiguous block of memory locations similar to Arrays in “C” programming while a List stores non-contiguous blocks and uses a double linked list.
  • Inserting and Deleting elements in a List is easier compared to Vector as in the latter, shifting of elements is required and it is a tedious process.
  • However sorting and searching are much faster in Vector compared to List and in former no traversal is required unlike List.
  • Lists support no numeric index like Array while Vector supports the same.
    • Insertion and Deletion of elements in List has no iterator validation unlike Vector where the same is possible.

You can make a class virtual if it is a base class that has been

passed to more than one derived class, as might happen with multiple

inheritance.

A base class can't be specified more than once in a derived class:

 class B { ...};
 class D : B, B { ... };  // ILLEGAL

However, a base class can be indirectly passed to the derived class more than once:

 class X : public B { ... }
 class Y : public B { ... }
 class Z : public X, public Y { ... }  // OK

In this case, each object of class Z will have two sub-objects of class B.

If this causes problems, you can add the keyword "virtual" to a base class

specifier. For example,

 class X : virtual public B { ... }
 class Y : virtual public B { ... }
 class Z : public X, public Y { ... }

B is now a virtual base class, and class Z has only one sub-object of class

B.

Constructors for Virtual Base Classes:

Constructors for virtual base classes are invoked before any non-virtual base classes. If the hierarchy contains multiple virtual base classes, the virtual base class constructors are invoked in the order in which they were declared. Any non-virtual bases are then constructed before the derived class

constructor is called. If a virtual class is derived from a non-virtual base, that non-virtual base will be first, so that the virtual base class can be properly constructed. For example, this code

 class X : public Y, virtual public Z
    X one;
produces this order:
 Z();   // virtual base class initialization
 Y();   // non-virtual base class
 X();   // derived class

Expect to come across this popular question in advanced C++ interview questions.

An abstract class is a class which has at least one pure virtual function. An abstract class can't be instantiated be can be overridden in a derived class as below:

//Example below:

class Base {
public:
virtual void Get() = 0;
virtual bool Get(int i) = 0;
virtual int Get(float x) = 0;
virtual ~Base() { }
};
class Derived1 : public Base {
bool value;
public:
void Get() { }
bool Get(int i) { return i;}
int Get(float x) { return (int)x;}
};
class Derived2 : public Base {
int value;
public:
void Get() { }
bool Get(int i) { return i;}
int Get(float x) { return (int)x;}
};
int main()
{
int k=5;
int temp = base->Get(k);  
cout<<"temp is"<<base->Get(k)<<endl;
return 0;
}
#include <stdexcept>
#include <iostream>
#include <vector>
#include <utility>
#include <unordered_map>
using namespace std;
class TwoSum
{
public:
  static pair<int, int> findTwoSum(const std::vector<int>& list, int sum)
  {
     unordered_map<int,int> s;
     for (size_t i = 0; i < list.size(); ++i)
     {
        auto j = s.find(sum - list[i]);
        if (j != s.end())
          return make_pair(i,j->second);
        s[list[i]] = i;
     }
     return make_pair(-1, -1);
  }
};
#ifndef RunTests
int main(int argc, const char* argv[])
{
  std::vector<int> list;
  list.push_back(3);
  list.push_back(1);
  list.push_back(5);
  list.push_back(7);
  list.push_back(5);
  list.push_back(9);
  pair<int, int> indices = TwoSum::findTwoSum(list, 12);
  cout << indices.first << '\n' << indices.second;
  return 0;
}
#endif

Output is:

3
2
#include <iostream>
// M x N matrix
#define M 4
#define N 5
// Dynamically Allocate Memory for 2D Array in C++
int main()
{
// dynamically allocate memory of size M*N
int* A = new int[M * N];
// assign values to allocated memory
for (int i = 0; i < M; i++)
for (int j = 0; j < N; j++)
*(A + i*N + j) = rand() % 100;
// print the 2D array
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
std::cout << *(A + i*N + j) << " ";    // or (A + i*N)[j])
std::cout << std::endl;
}
// deallocate memory
delete[] A;
return 0;
}
#include <string>
#include <stdexcept>
#include <iostream>
using namespace std;
class Palindrome
{
public:
   static bool isPalindrome(const std::string& word)
   {
       static int i,j;
       static int count;
       while(word[count]!='\0')
           count++;
       cout<<"count is"<<count<<endl;
       i=0;
       j=count-1;
       while(i<j)
       {
           cout<<endl<<"word[i]"<<word[i]<<endl<<"word[j]"<<word[j]<<endl;
           if(tolower(word[i++])!=tolower(word[j--]))
           {
               cout<<endl<<word<<" is not a Palindrome"<<endl;
               return 0;
           }
       }
       cout<<endl<<word<<" is a palindrome"<<endl;
       count = i = i= 0;
       return 1;
   }
};
#ifndef RunTests
int main()
{
    std::cout << Palindrome::isPalindrome("Deleveled");
    std::cout << Palindrome::isPalindrome("Malayalam");
    std::cout << Palindrome::isPalindrome("Bab");
    std::cout << Palindrome::isPalindrome("Balam");
}
#endif

Upcasting is converting a derived class reference or pointer to a base class. In other words, upcasting allows us to treat a derived type as though it were its base type. It is always allowed for public inheritance, without an explicit type cast. This is a result of the is-a relationship between the base and derived classes. Upcasting allows us to treat a derived type as though it were its base type.

When a derived class object is passed by value as a base class object, the specific behaviors of a derived class object are sliced off. We're left with a base class object. In other words, if we upcast (Upcasting and Down Casting) to an object instead of a pointer or reference, the object is sliced. As a result, all that remains is the sub object that corresponds to the destination type of our cast and which is only a part of the actual derived class.

Converting a base-class pointer (reference) to a derived-class pointer (reference) is called downcasting. Downcasting is not allowed without an explicit typecast. The reason for this restriction is that the is-a relationship is not, in most of the cases, symmetric. A derived class could add new data members, and the class member functions that used these data members wouldn't apply to the base class.

//Example of upcasting and downcasting:

class Parent {
public:
 void sleep() {}
};
class Child: public Parent {
public:
 void gotoSchool(){}
};
int main( )
{
 Parent parent;
 Child child;
 // upcast - implicit type cast allowed
 Parent *pParent = &child;
 // downcast - explicit type case required
 Child *pChild =  (Child *) &parent;
 pParent -> sleep();
 pChild -> gotoSchool();
 return 0;
}

In C++, RTTI (Run-time type information) is a mechanism that exposes information about an object’s data type at runtime and is available only for the classes which have at least one virtual function. It allows the type of an object to be determined during program runtime execution

For example, dynamic_cast uses RTTI and following program fails with error “cannot dynamic_cast `b’ (of type `class B*’) to type `class D*’ (source type is not polymorphic) ” because there is no virtual function in the base class B.

// CPP program to illustrate  
// Run Time Type Identification  
#include<iostream>
using namespace std;
class B { };
class D: public B {};
int main()
{
   B *b = new D;
   D *d = dynamic_cast<D*>(b);
   if(d != NULL)
       cout<<"works";
   else
       cout<<"cannot cast B* to D*";
   getchar();
   return 0;
}
//This is give a run time error: “cannot dynamic_cast 'b' (of type 'class B*') to type 'class D*' (source type is not polymorphic)”
//Adding a virtual function to the base class B makes it working.
// CPP program to illustrate  
// Run Time Type Identification  
#include<iostream>
using namespace std;
class B { virtual void fun() {} };
class D: public B { };
int main()
{
   B *b = new D;
   D *d = dynamic_cast<D*>(b);
   if(d != NULL)
       cout << "works";
   else
       cout << "cannot cast B* to D*";
   getchar();
   return 0;
}

Using pthread_create we create a thread. We can use the reference of a structure to pass multiple arguments to the 4th parameter as below:

#include <iostream.h>
#include <pthread.h>
struct arg_struct {
   int arg1;
   int arg2;
};
void *print_the_arguments(void *arguments)
{
   struct arg_struct *args = (struct arg_struct *)arguments;
   cout<< args -> arg1<<endl;
   cout<< args -> arg2<<endl;
   pthread_exit(NULL);
   return NULL;
}
int main()
{
   pthread_t some_thread;
   struct arg_struct args;
   args.arg1 = 5;
   args.arg2 = 7;
   if (pthread_create(&some_thread, NULL, &print_the_arguments, (void *)&args) != 0) {
       printf("Uh-oh!\n");
       return -1;
   }
   return pthread_join(some_thread, NULL); /* Wait until thread is finished */
}
   return pthread_join(some_thread, NULL); /* Wait until thread is finished */
}

We cant make a class constructor virtual in C++ to create polymorphic objects. C++ being static typed (the purpose of RTTI is different) language, it is meaningless to the C++ compiler to create an object polymorphically. The compiler must be aware of the class type to create the object. In other words, what type of object to be created is a compile time decision from C++ compiler perspective. If we make constructor virtual, compiler flags an error. In fact except inline, no other keyword is allowed in the declaration of constructor.

Deleting a derived class object using a pointer to a base class that has a non-virtual destructor results in undefined behavior. To correct this situation, the base class should be defined with a virtual destructor. For example, following program results in undefined behavior.

// CPP program without virtual destructor 
// causing undefined behavior
#include<iostream>
using namespace std;
class base {
  public:
    base()     
    { cout<<"Constructing base \n"; }
    ~base()
    { cout<<"Destructing base \n"; }     
};
class derived: public base {
  public:
    derived()     
    { cout<<"Constructing derived \n"; }
    ~derived()
    { cout<<"Destructing derived \n"; }
};
int main(void)
{
  derived *d = new derived();  
  base *b = d;
  delete b;
  getchar();
  return 0;
}

It's no surprise that this one pops up often in C++ programming interview questions.

A Sparse Matrix is an array of elements in which many elements have a value of zero.

#include <string.h>
#include <iostream>
#include <map>
#include <utility>
using namespace std;
int main()
{
  map<int, string> Employees;
  // 1) Assignment using array index notation
  Employees[5234] = "Mike C.";
  Employees[3374] = "Charlie M.";
  Employees[1923] = "David D.";
  Employees[7582] = "John A.";
  Employees[5328] = "Peter Q.";
 cout << "Employees[3374]=" << Employees[3374] << endl << endl;
 cout << "Map size: " << Employees.size() << endl;
 cout << endl << "Natural Order:" << endl;
 for( map<int,string>::iterator ii=Employees.begin(); ii!=Employees.end(); ++ii)
{
      cout << (*ii).first << ": " << (*ii).second << endl;
            }
  cout << endl << "Reverse Order:" << endl;
for( map<int,string>::reverse_iterator ii=Employees.rbegin(); ii!=Employees.rend(); ++ii)
{
      cout << (*ii).first << ": " << (*ii).second << endl;
}
}

Output:

Employees[3374]=Charlie M.
Map size: 5
Natural Order:
1923: David D.
3374: Charlie M.
5234: Mike C.
5328: Peter Q.
7582: John A.
Reverse Order:
7582: John A.
5328: Peter Q.
5234: Mike C.
3374: Charlie M.
1923: David D.

Below is the logic for the implementation of the above logic

In the en-queue operation, the new element is entered at the top of Stack1. In de-queue operation, if Stack2 is empty then all the elements are moved to Stack2 and top of Stack2 is returned.

enQueue(q, k):

Push the element ‘k’ to Stack1

deQueue(q):

While Stack1 is not empty and Stack2 is empty, pop the elements from Stack1 and push to Stack2.

The top of the Stack2 popped out is returned.

Program to perform the above:

#include <iostream>
using namespace std;
// implementing the stack class
class Stack
{
   int top;
   public:
   int a[10];  //Maximum size of Stack
   Stack()
   {
       top = -1;
   }
   // declaring all the function
   void push(int x);
   int pop();
   bool isEmpty();
};
// function to insert data into stack
void Stack::push(int x)
{
   if(top >= 10)
   {
       cout << "Stack Overflow";
   }
   else
   {
       a[++top] = x;
       cout << endl<<  "Element Inserted into Stack"<< x ;
   }
}
// function to remove data from the top of the stack
int Stack::pop()
{
   if(top < 0)
   {
       cout << "Stack Underflow \n";
       return 0;
   }
   else
   {
       return (a[top--]);
   }
}
// function to check if stack is empty
bool Stack::isEmpty()
{
   if(top < 0)
   {
       return true;
   }
   else
   {
       return false;
   }
}
// implementing the queue class
class Queue {
   public:
   Stack S1, S2;
   //declaring enqueue method
   void enqueue(int x);
   //declaring dequeue method
   int dequeue();
};
// enqueue function
void Queue :: enqueue(int x)
{
   S1.push(x);
   cout << "Element Inserted into Queue "<< x << endl;
}
// dequeue function
int Queue :: dequeue()
{
   int x, y;
   while(!S1.isEmpty())
   {
       // take an element out of first stack
       x = S1.pop();
       // insert it into the second stack
       S2.push(x);
   }
   // removing the element
   y = S2.pop();
   // moving back the elements to the first stack
   while(!S2.isEmpty())
   {
       x = S2.pop();
       S1.push(x);
   }
   return y;
}
// main function
int main()
{
   Queue q;
   q.enqueue(10);
   q.enqueue(100);
   q.enqueue(1000);
   cout << endl<< "Removing element from queue" << q.dequeue();
   return 0;
}

Output:

Element Inserted into Stack10Element Inserted into Queue 10
Element Inserted into Stack100Element Inserted into Queue 100
Element Inserted into Stack1000Element Inserted into Queue 1000
Element Inserted into Stack1000
Element Inserted into Stack100
Element Inserted into Stack10
Element Inserted into Stack100
Element Inserted into Stack1000
Removing element from queue10

The above can be demonstrated using the below program:        

static int count=0;
class Message
{
public:
void put_message(void);
void get_message(void);
int message;
Message(void)
{
message=0;
cout<<"Objects Created"<<endl;
}
Message(int k)
{
message=k;
}
~Message() {
cout<<"Objects Destroyed"<<endl;
}
}q;
void Message::put_message(void)
{
message=12345;
}
void Message::get_message(void)
{
cout<<"The message is "<<message<<endl;
}
int main()
{
Message k(67890);
q.put_message();
q.get_message();
k.get_message();
return 0;
}

Output:

Objects Created
The message is 12345
The message is 67890
Objects Destroyed
Objects Destroyed

Description

C++ is an object-oriented and generic programming language utilized with system/application software and, client-server applications, embedded firmware. It has a collection of predefined classes. Predefined classes are data types that can be incorporated multiple times. C++ incorporates several operators such as arithmetic, comparison, logical operations and bit manipulation. It enables the overloading of certain operations like addition. It is popularly used in embedded system software engineering, gaming and communication. Other industries which use C++ are finance, health care, and defense.

Companies around the globe use and integrate C++. Companies that use C++ are Google, Lyft, Twitch, etc. Companies that integrate C++ are Bazel, IBM DB2, Conan, etc. Professionals can opt to be a C++ Software Engineer, C++ Developer, Senior C++ Developer, C++ Development Manager, etc. According to Payscale.com, the average salary of a C++ software engineer is $81,899 per year.

Worried about your C++ interview? We have got the perfect rescue for you wherein you will be advised on the most common C++ interview questions with answers. Rest assured; we offer you the most frequently asked interview questions on C++ to help you clear your upcoming C++ job interview. If you're a beginner, join us in our programming certifications for beginners to lay a strong foundation for your career. 

The possibility of these C++ interview questions being asked in a C++ interview is high. How will one be able to crack a C++ interview? How to get through the interview? Small steps that needed to be taken at the least to face a C++ Interview have been discussed here. These C++ interview questions for experienced and freshers will help you attain the skills and confidence required to ace the interview. To make yourself prepared in the best possible way, enroll in a programming online course to strengthen your base.

Read More
Levels