C++ Interview Questions All Together by CMK
C++ Interview Questions All Together by CMK
C++ Interview Questions All Together by CMK
C structure can't contain functions means only data members are allowed, but structure in C++ can have both
functions & data members.
struct keyword is necessary in C to create structure type variable, but it is redundant & not necessary in C++.
Size of empty structure is undefined behavior in C, but it is always 1 in C++.
Structure in C can't have static members, but C++ structure can have static members.
For example, following program fails in compilation in C but compiles fine in C++.
#include <stdio.h>
struct demo
{
static int a;
};
int main()
{ return 0; }
Structure members can't be directly initialized inside the struct in C, but it is allowed in C++ since C++11. (Thanks to
in class member initializers)
// Invalid C, but valid C++ program
#include <stdio.h>
struct stu{
int a=9;
};
int main(){
struct stu s;
printf("%d",s.a);
}
We can have both pointers and references to struct in C++, but only pointers to structs are allowed. (References
aren't feature of C language).
C++ also have .* and -> operators to access individual members of struct, but C doesn't have such kind of
operators.
Struct declaration establishes a scope in C++ and not in C, which makes member enumerators and nested structs
possible in C++ (you can *write* them inside a struct in C, but they escape and become local to whatever function
the parent struct is in).
In C, we need to use struct tag whenever we declare a struct variable. In C++, the struct tag is not necessary. For
example, let there be a structure for Student. In C, we must use ‘struct Student‘ for Student variables. In C++, we
can omit struct and use ‘Student‘ only.
Following is a program that is based on the fact and produces different outputs in C and C++. It prints sizeof(int) in
C and sizeof(struct T) in C++.
#include <stdio.h>
int T;
int main()
{
struct T { double x; }; // In C++, this T hides the global variable T,
// but not in C
printf("%d", sizeof(T));
return 0;
}
C places struct tags and ordinary identifiers in different name spaces, in C++ they are in the same name space (not
to be confused with namespace), which is why that struct T hides the global T in C++, but not in C.
1. C++ is Multi-Paradigm ( not pure OOP, supports both procedural and object oriented) while C
follows procedural style programming.
2. In C data security is less, but in C++ you can use modifiers for your class members to make it
inaccessible from outside.
3. C follows top-down approach ( solution is created in step by step manner, like each step is
processed into details as we proceed ) but C++ follows a bottom-up approach ( where base
elements are established first and are linked to make complex solutions ).
4. C++ supports function overloading while C does not support it.
5. C++ allows use of functions in structures, but C does not permit that.
6. C++ supports reference variables ( two variables can point to same memory location ). C
does not support this.
7. C does not have a built in exception handling framework, though we can emulate it with other
mechanism. C++ directly supports exception handling, which makes life of developer easy.
What is a class?
[Probably this would be the first question for a Java/c++ technical interview for fresher’s and sometimes for
experienced as well. Try to give examples when you answer this question.]
Class defines a datatype, it's type definition of category of thing(s). But a class actually does not define the data,
it just specifies the structure of data. To use them you need to create objects out of the class. Class can be
considered as a blueprint of a building, you cannot stay inside blueprint of building, you need to construct
building(s) out of that plan. You can create any number of buildings from the blueprint, similarly you can create
any number of objects from a class.
class Vehicle
{
public:
int numberOfTyres;
double engineCapacity;
void drive(){
// code to drive the car
}
};
3. What is an Object/Instance?
Object is the instance of a class, which is concrete. From the above example, we can create instance of class
Vehicle as given below
Vehicle vehicleObject;
We can have different objects of the class Vehicle, for example we can have Vehicle objects with 2 tyres, 4tyres
etc. Similarly different engine capacities as well.
private:
Members declared as private are accessible only with in the same class and they cannot be accessed outside
the class they are declared.
public:
Members declared as public are accessible from any where.
protected:
Members declared as protected can not be accessed from outside the class except a child class. This access
specifier has significance in the context of inheritance.
Encapsulation
Encapsulation is the mechanism by which data and associated operations/methods are bound together and thus
hide the data from outside world. It's also called data hiding. In c++, encapsulation achieved using the access
specifiers (private, public and protected). Data members will be declared as private (thus protecting from direct
access from outside) and public methods will be provided to access these data. Consider the below class
class Person
{
private:
int age;
public:
int getAge(){
return age;
}
int setAge(int value){
if(value > 0){
age = value;
}
}
};
In the class Person, access to the data field age is protected by declaring it as private and providing public access
methods. What would have happened if there was no access methods and the field age was public? Anybody
who has a Person object can set an invalid value (negative or very large value) for the age field. So by
encapsulation we can preventing direct access from outside, and thus have complete control, protection and
integrity of the data.
Data abstraction
Data abstraction refers to hiding the internal implementations and show only the necessary details to the outside
world. In C++ data abstraction is implemented using interfaces and abstract classes.
class Stack
{
public:
virtual void push(int)=0;
virtual int pop()=0;
};
public:
void push(int) {
// implement push operation using array
}
int pop(){
// implement pop operation using array
}
};
In the above example, the outside world only need to know about the Stack class and its push, pop operations.
Internally stack can be implemented using arrays or linked lists or queues or anything that you can think of. This
means, as long as the push and pop method performs the operations work as expected, you have the freedom to
change the internal implementation with out affecting other applications that use your Stack class.
Inheritance
Inheritance allows one class to inherit properties of another class. In other words, inheritance allows one class
to be defined in terms of another class.
class SymmetricShape
{
public:
int getSize()
{
return size;
}
void setSize(int w)
{
size = w;
}
protected:
int size;
};
// Derived class
class Square: public SymmetricShape
{
public:
int getArea()
{
return (size * size);
}
};
In the above example, class Square inherits the properties and methods of class SymmetricShape. Inheritance
is the one of the very important concepts in C++/OOP. It helps to modularise the code, improve reusability and
reduces tight coupling between components of the system.
int i = 10;
variable i will get initialized to 10.
int i(10);
In the above example, variable a will get automatically promoted from short to int. This is called implicit
conversion/coercion in c++.
int main( )
{
cout << "min (20,10): " << min(20,10) << endl;
cout << "min (0,200): " << min(0,200) << endl;
cout << "min (100,1010): " << min(100,1010) << endl;
return 0;
}
If the complier decides to make the function min as inline, then the above code will internally look as if it was
written like
int main( )
{
cout << "min (20,10): " << ((20 < 10)? 20 : 10) << endl;
cout << "min (0,200): " << ((0 < 200)? 0 : 200) << endl;
cout << "min (100,1010): " << ((100 < 1010)? 100 : 1010) << endl;
return 0;
}
10. What do you mean by translation unit in c++?
We organize our C++ programs into different source files (.cpp, .cxx etc). When you consider a source file, at
the preprocessing stage, some extra content may get added to the source code ( for example, the contents of
header files included) and some content may get removed ( for example, the part of the code in the #ifdef of
#ifndef block which resolve to false/0 based on the symbols defined). This effective content is called a translation
unit. In other words, a translation unit consists of
11. What do you mean by internal linking and external linking in c++?
[This interview question is related to questions on "translation unit" and "storage classes"]
A symbol is said to be linked internally when it can be accessed only from with-in the scope of a single translation
unit. By external linking a symbol can be accessed from other translation units as well. This linkage can be
controlled by using static and extern keywords.
auto
It's the default storage class for local variables. They can be accessed only from with in the declaration scope.
auto variables are allocated at the beginning of enclosing block and deallocated at the end of enclosing block.
1. void changeValue(void)
2. {
3. auto int i = 1 ;
4. i++;
5. printf ( "%d ", i ) ;
6.
7. }
8. int main()
9. {
10. changeValue();
11. changeValue();
12. changeValue();
13. changeValue();
14. return 0;
15. }
16.
17. Output:-
18. 2222
In the above example, every time the method changeValue is invoked, memory is allocated for i and de allocated
at the end of the method. So it's output will be same.
register
It's similar to auto variables. Difference is that register variables might be stored on the processor register instead
of RAM, that means the maximum size of register variable should be the size of CPU register ( like 16bit, 32bit
or 64bit). This is normally used for frequently accessed variables like counters, to improve performance. But
note that, declaring a variable as register does not mean that they will be stored in the register. It depends on the
hardware and implementation.
1. int main()
2. {
3. register int i;
4. int array[10] = {0,1,2,3,4,5,6,7,8,9};
5.
6. for (i=0;i<10;i++)
7. {
8. printf("%d ", array[i]);
9. }
10. return 0;
11. }
12.
13. Output:-
14. 0123456789
The variable i might be stored on the CPU register and due to which the access of i in the loop will be faster.
static
A static variable will be kept in existence till the end of the program unlike creating and destroying each time
they move into and out of the scope. This helps to maintain their value even if control goes out of the scope.
When static is used with global variables, they will have internal linkage, that means it cannot be accessed by
other source files. When static is used in case of a class member, it will be shared by all the objects of a class
instead of creating separate copies for each object.
1. void changeValue(void)
2. {
3. static int i = 1 ;
4. i++;
5. printf ( "%d ", i ) ;
6.
7. }
8.
9. int main()
10. {
11. changeValue();
12. changeValue();
13. changeValue();
14. changeValue();
15. return 0;
16. }
17.
18. Output:-
19. 2345
Since static variable will be kept in existence till the end of program, variable i will retain it's value across the
method invocations.
extern
extern is used to tell compiler that the symbol is defined in another translation unit (or in a way, source files) and
not in the current one. Which means the symbol is linked externally. extern symbols have static storage duration,
that is accessible through out the life of program. Since no storage is allocated for extern variable as part of
declaration, they cannot be initialized while declaring.
1. int x = 10;
2. int main( )
3. {
4. extern int y ;
5. printf("x: %d ", x );
6. printf("y: %d", y);
7. return 0;
8. }
9. int y = 70 ;
10.
11. Output:-
12. x: 10 y: 70
extern variable is like global variable, it's scope is through out the program. It can be defined anywhere in the
c++ program.
mutable
mutable storage class can be used only on non static non const data a member of a class. Mutable data member
of a class can be modified even is it's part of an object which is declared as const.
1. class Test
2. {
3. public:
4. Test(): x(1), y(1) {};
5. mutable int x;
6. int y;
7. };
8.
9. int main()
10. {
11. const Test object;
12. object.x = 123;
13. //object.y = 123;
14. /*
15. * The above line if uncommented, will create compilation error.
16. */
17. cout<< "X:"<< object.x << ", Y:" << object.y;
18. return 0;
19. }
20.
21. Output:-
22. X:123, Y:1
In the above example, we are able to change the value of member variable x though it's part of an object which
is declared as const. This is because the variable x is declared as mutable. But if you try to modify the value of
member variable y, compiler will throw error.
You can find the summary of c++ storage class specifiers below
Memory
auto Local With in function
(RAM)
Memory Life time is from when the flow reaches the first
static Local
(RAM) declaration to the termination of program.
CPU
register Local With in function
register
Memory
extern Global Till the end of main program
(RAM)
1. class SampleClass{
2. public:
3. int* ptr;
4. SampleClass();
5. // Copy constructor declaration
6. SampleClass(SampleClass &obj);
7. };
8.
9. SampleClass::SampleClass(){
10. ptr = new int();
11. *ptr = 5;
12. }
13.
14. // Copy constructor definition
15. SampleClass::SampleClass(SampleClass &obj){
16. //create a new object for the pointer
17. ptr = new int();
18. // Now manually assign the value
19. *ptr = *(obj.ptr);
20. cout<<"Copy constructor...\n";
21. }
This function is used to change the size of memory object pointed by address ptr to the size given by size. If ptr
is a null pointer, then realloc will behave like malloc(). If the ptr is an invalid pointer, then defined behaviour
may occur depending the implementation. Undefined behaviour may occur if the ptr has previously been
deallocated by free(), or dealloc() or ptr do not match a pointer returned by an malloc(), calloc() or realloc().
This function is used to deallocate a block of memory that was allocated using malloc(), calloc() or realloc(). If
ptr is null, this function does not doe anything.
16. What is difference between shallow copy and deep copy? Which is default?
[This question can be expected in any interviews, not just c++ interviews. This is a usual question in most of
the java interviews.]
When you do a shallow copy, all the fields of the source object is copied to target object as it is. That means, if
there is a dynamically created field in the source object, shallow copy will copy the same pointer to target object.
So you will have two objects with fields that are pointing to same memory location which is not what you usually
want.
In case of deep copy, instead of copying the pointer, the object itself is copied to target. In this case if you modify
the target object, it will not affect the source. By default copy constructors and assignment operators do shallow
copy. To make it as deep copy, you need to create a custom copy constructor and override assignment operator.
Technically it is possible to generate the source code from binary. It is called reverse engineering. There are lot of reverse
engineering tools available. But, in actual case most of them will not re generate the exact source code back because many
information will be lost due to compiler optimization and other interpretations.
1. class Base
2. {
3. int a;
4. public:
5. Base()
6. {
7. a = 1;
8. }
9. virtual void method()
10. {
11. cout << a;
12. }
13. };
14.
15. class Child: public Base
16. {
17. int b;
18. public:
19. Child()
20. {
21. b = 2;
22. }
23. virtual void method()
24. {
25. cout << b;
26. }
27. };
28.
29. int main()
30. {
31. Base *pBase;
32. Child oChild;
33. pBase = &oChild;
34. pBase->method();
35. return 0;
36. }
In the above example even though the method in invoked on Base class reference, method of the child will get
invoked since its declared as virtual.
20. What do you mean by pure virtual functions in C++? Give an example?
Pure virtual function is a function which doesn't have an implementation and the same needs to be
implemented by the the next immediate non-abstract class. (A class will become an abstract class if
there is at-least a single pure virtual function and thus pure virtual functions are used to create
interfaces in c++).
1. class SymmetricShape {
2. public:
3. // draw() is a pure virtual function.
4. virtual void draw() = 0;
5. };
21. Why pure virtual functions are used if they don't have implementation / when does a pure virtual function
become useful?
Pure virtual functions are used when it doesn't make sense to provide definition of a virtual function in the base class or
a proper definition does not exists in the context of base class. Consider the above example, class Symmetric Shape is
used as base class for shapes with symmetric structure (Circle, square, equilateral triangle etc.). In this case, there exists
no proper definition for function draw() in the base class Symmetric Shape instead the child classes of Symmetric Shape
(Circle, Square etc.) can implement this method and draw proper shape.
23. What you mean by early binding and late binding? How it is related to dynamic binding?
[This c++ interview question is related to question about virtual functions]
Binding is the process of linking actual address of functions or identifiers to their reference. This happens mainly two
times.
For all the direct function references compiler will replace the reference with actual address of the method.
In case of virtual function calls using a Base reference, as in shown in the example of question no: 2, compiler
does not know which method will get called at run time. In this case compiler will replace the reference with
code to get the address of function at runtime.
In C++, reference variable allows you create an alias (second name) for an already existing variable. A reference variable
can be used to access (read/write) the original data. That means, both the variable and reference variable are attached to
same memory location. In effect, if you change the value of a variable using reference variable, both will get changed
(because both are attached to same memory location).
1. int a = 20;
2. int& b = a;
3.
The first statement initializes an integer variable to a. Second statement creates an integer reference
initialized to variable a
Take a look at the below example to see how reference variables work.
1. int main ()
2. {
3. int a;
4. int& b = a;
5.
6. a = 10;
7. cout << "Value of a : " << a << endl;
8. cout << "Value of a reference (b) : " << b << endl;
9.
10. b = 20;
11. cout << "Value of a : " << a << endl;
12. cout << "Value of a reference (b) : " << b << endl;
13.
14. return 0;
15. }
25. What are the difference between reference variables and pointers in C++?
[This question is usually asked in a twisted way during c++ interviews. Sometimes the interviewer might use
examples and ask you to find the error.]
Pointers can be (re)pointed to any object, Reference variables should be initialized with an object
at any time, any number of times during when they are created and they cannot be reinitialized
the execution. to refer to another object
Pointer has own memory address and Reference variables has location on stack, but shares
location on stack the same memory location with the object it refer to.
Introduction
Upcasting and downcasting are an important part of C++. Upcasting and downcasting gives a
possibility to build complicated programs with a simple syntax. It can be achieved by using
Polymorphism.
C++ allows that a derived class pointer (or reference) to be treated as base class pointer. This is
upcasting.
Downcasting is an opposite process, which consists in converting base class pointer (or reference)
to derived class pointer.
Upcasting and downcasting should not be understood as a simple casting of different data types. It
can lead to a great confusion.
In this topic, we will use the following hierarchy of classes:
As you can see, Manager and Clerk are both Employee. They are both Person too. What does it
mean? It means that Manager and Clerk classes inherit properties of Employee class, which inherits
properties of Person class.
For example, we don't need to specify that both Manager and Clerk are identified by First and Last
name, have salary; you can show information about them and add a bonus to their salaries. We
have to specify these properties only once in the Employee class:
In the same time, Manager and Clerk classes are different. Manager takes a commission fee for
every contract, and Clerk has information about his Manager:
Try It
#include <iostream>
using namespace std;
class Person
{
//content of Person
};
int main()
{
//pointer to base class object
Employee* emp;
//implicit upcasting
emp = &m1;
//It's ok
cout<<emp->FirstName<<endl;
cout<<emp->salary<<endl;
congratulate(&c1);
congratulate(&m1);
Manager and Clerk are always Employees. Moreover, Employee is a Person. Therefore, Manager
and Clerk are Persons too. You have to understand it before we start learning upcasting and
downcasting.
Both upcasting and downcasting do not change object by itself. When you use upcasting or
downcasting you just "label" an object in different ways.
UPCASTING
Upcasting is a process of treating a pointer or a reference of derived class object as a base class
pointer. You do not need to upcast manually. You just need to assign derived class pointer (or
reference) to base class pointer:
When you use upcasting, the object is not changing. Nevertheless, when you upcast an object, you
will be able to access only member functions and data members that are defined in the base class:
//It's ok
emp->FirstName;
emp->salary;
//Fails because upcasting is used
emp->getComm();
This function will work with all the classes that are derived from the Employee class. When you call it
with objects of type Manager and Person, they will be automatically upcasted to Employee class:
//automatic upcasting
congratulate(&c1);
congratulate(&m1);
Of course, this model is simplified view of memory layout for objects. However, it represents the fact
that when you use base class pointer to point up an object of the derived class, you can access only
elements that are defined in the base class (green area). Elements of the derived class (yellow area)
are not accessible when you use base class pointer.
DOWNCASTING
Downcasting is an opposite process for upcasting. It converts base class pointer to derived class
pointer. Downcasting must be done manually. It means that you have to specify explicit type cast.
Downcasting is not safe as upcasting. You know that a derived class object can be always treated
as base class object. However, the opposite is not right. For example, a Manager is always a
Person; But a Person is not always a Manager. It could be a Clerk too.
You have to use an explicit cast for downcasting:
e1 object is not an object of Manager class. It does not contain any information about commission.
That why such an operation can produce unexpected results.
Look on the memory layout again:
When you try to downcast base class pointer (Employee) that is not actually pointing up an object of
derived class (Manager), you will get access to the memory that does not have any information
about derived class object (yellow area). This is the main danger of downcasting.
You can use a safe cast that can help you to know, if one type can be converted correctly to another
type. For this purpose, use dynamic cast.
Dynamic Cast
dynamic_cast is an operator that converts safely one type to another type. In the case, the
conversation is possible and safe, it returns the address of the object that is converted. Otherwise, it
returns nullptr.
dynamic_cast has the following syntax
dynamic_cast<new_type> (object)
If you want to use dynamic cast for downcasting, base class should be polymorphic - it must have at
least one virtual function. Modify base class Person by adding a virtual function:
Now you can use downcasting for converting Employee class pointers to derived classes pointers.
In this case, dynamic cast returns nullptr. Therefore, you will see a warning message.
1. Class name must start with an uppercase letter. If class name is made of more than one word,
then first letter of each word must be in uppercase. Example,
2. Classes contain, data members and member functions, and the access of these data members
and variable depends on the access specifiers (discussed in next section).
3. Class's member functions can be defined inside the class definition or outside the class
definition.
4. Class in C++ are similar to structures in C, the only difference being, class defaults to private
access control, where as structure defaults to public.
5. All the features of OOPS, revolve around classes in C++. Inheritance, Encapsulation,
Abstraction etc.
6. Objects of class holds separate copies of data members. We can create as many objects of a
class as we need.
7. Classes do posses more characteristics, like we can create abstract classes, immutable classes,
1. Simple functions
2. Static functions
3. Const functions
4. Inline functions
5. Friend functions
int main()
{
X::f(); // calling member function directly with class name
}
These functions cannot access ordinary data members and member functions, but only static data
members and static member functions.
It doesn't have any "this" keyword which is the reason it cannot access ordinary members. We will
study about "this" keyword later.
Inline functions
All the member functions defined inside the class definition are by default declared as Inline. We will
study Inline Functions in details in the next topic.
Friend functions
Friend functions are actually not class member function. Friend functions are made to give private
access to non-class functions. You can declare a global function as friend, or a member function of
other class as friend.
Example :
class WithFriend
{
int i;
public:
friend void fun(); // Global function as friend
};
void fun()
{
WithFriend wf;
wf.i=10; // Access to private data member
cout << wf.i;
}
int main()
{
fun(); //Can be called directly
}
Hence, friend functions can access private data members by creating object of the class. Similarly
we can also make function of other class as friend, or we can also make an entire class as friend
class.
class Other
{
void fun();
};
class WithFriend
{
private:
int i;
public:
void getdata(); // Member function of class WithFriend
friend void Other::fun(); // making function of class Other as friend here
friend class Other; // making the complete class as friend
};
When we make a class as friend, all its member functions automatically become friend functions.
Friend Functions is a reason, why C++ is not called as a pure Object Oriented language. Because it
violates the concept of Encapsulation.
ESTABLISH MYSELF AS A GOOD TEAM MEMBER
DESCRIPTION
I established myself as a key member in the team related to Python and Shell scripting, I have helped
team to clarify doubts related to shell and python scripting related topics in project.
I have taken responsibility of sending daily and weekly status reports of off-shore team when my TL is on
vacation.
As I got opportunity to guide my teammates, I am getting experience related to next level of activities.
I would improve my communications skills, reach next level of proficiency in my skill set by attending
online and classroom trainings which would help me to get to my next level in career ladder.
DESCRIPTION
I would go through the existing code (C++, Python, PL/SQL) to understand the functionality and
technical concepts used to achieve it.
I make sure to use these while implementing my code.
Attending online trainings related to my skills, as per project requirements.
I have got knowledge on LATIS a Telecom building application. I have got understanding on various
modules of building application
Prior to this project I have got experience on SMSE applications related to Telecom. Now I have got
understanding about Telecom Billing application also.
I would reach next level of proficiency in my skill set by attending online and classroom trainings.
WORK ON THE ASSIGNED DELEVIRABLES
DESCRIPTION
Self-Inputs:
What are you most proud of?
I have involved in all the phases of SDLC from Requirement gathering, Coding, Testing and support while
implementing a new executable right from scratch.
I have created proto-type and functionality flow documentation for creation of new executable “state
change code”. I have implemented the executable code and Unit test automation script in Python.
Participated functional and code review discussions. I have created new python scripts for identifying
and deleting the duplicates records from the final output csv file as per client requirement.
Extensively work on the Unit testing of this executable by creating new Python script for testing the
executable, added test cases related to executable functionalities and created test data.
Ran unit tests, analyzed the results and send it for code review.
I have improved my communication skills as I was required interact with client on a day to day basis.
I have improved my coding standards as I have got opportunity to write 3K LOC and involved in code
review calls.
I would improve my communications skills, reach next level of proficiency in my skill set by attending
online and classroom trainings.
In SQL, a join is used to compare and combine — literally join — and return
specific rows of data from two or more tables in a database. An inner join finds
and returns matching data from tables, while an outer join finds and returns
matching data and some dissimilar data from tables.
Inner Join
An inner join focuses on the commonality between two tables. When using an inner join, there
must be at least some matching data between two (or more) tables that are being compared. An
inner join searches tables for matching or overlapping data. Upon finding it, the inner join
combines and returns the information into one new table.
Example of Inner Join
Let's consider a common scenario of two tables: product prices and quantities. The common
information in the two tables is product name, so that is the logical column to join the tables on.
There are some products that are common in the two tables; others are unique to one of the tables
and don't have a match in the other table.
An inner join on Products returns information about only those products that are common in
both tables.
Outer Join
An outer join returns a set of records (or rows) that include what an inner join would return but
also includes other rows for which no corresponding match is found in the other table.
There are three types of outer joins:
Left Outer Join (or Left Join)
Right Outer Join (or Right Join)
Full Outer Join (or Full Join)
Each of these outer joins refers to the part of the data that is being compared, combined, and
returned. Sometimes nulls will be produced in this process as some data is shared while other
data is not.
Left Outer Join
A left outer join will return all the data in Table 1 and all the shared data (so, the inner part of the
Venn diagram example), but only corresponding data from Table 2, which is the right join.
Left Join Example
In our example database, there are two products — oranges and tomatoes — on the 'left' (Prices
table) that do not have a corresponding entry on the 'right' (Quantities table). In a left join, these
rows are included in the result set with a NULL in the Quantity column. The other rows in the
result are the same as the inner join.
Right Outer Join
A right outer join returns Table 2's data and all the shared data, but only corresponding data from
Table 1, which is the left join.
Right Join Example
Similar to the left join example, the output of a right outer join includes all rows of the inner join
and two rows — broccoli and squash — from the 'right' (Quantities table) that do not have
matching entries on the left.
Full Outer Join
A full outer join, or full join, which is not supported by the popular MySQL database
management system, combines and returns all data from two or more tables, regardless of
whether there is shared information. Think of a full join as simply duplicating all the specified
information, but in one table, rather than multiple tables. Where matching data is missing, nulls
will be produced.
These are just the basics, but many things can be done with joins. There are even joins that can
exclude other joins!
Upcasting in C++
Upcasting is using the Super class's reference or pointer to refer to a Sub class's object. Or we can
say that, the act of converting a Sub class's reference or pointer into its Super class's reference or
pointer is called Upcasting.
class Super
{ int x;
public:
void funBase() { cout << "Super function"; }
};
int main()
{
Super* ptr; // Super class pointer
Sub obj;
ptr = &obj;
The opposite of Upcasting is Downcasting, in which we convert Super class's reference or pointer
into derived class's reference or pointer. We will study more about Downcasting later
Constructors and Destructors are never inherited and hence never overrided.
Also, assignment operator = is never inherited. It can be overloaded but can't be inherited by sub
class.
In this case both class B and C inherits function show() from class A. Hence class D has two
inherited copies of function show(). In main() function when we call function show(), then ambiguity
arises, because compiler doesn't know which show() function to call. Hence we use Virtual keyword
while inheriting class.
class B : virtual public A {};
Now by adding virtual keyword, we tell compiler to call any one out of the two show() funtions.
before class D's constructor, constructors of its super classes will be called, hence constructors
of class B, class C and class A will be called.
when constructors of class B and class C are called, they will again make a call to their super
class's constructor.
This will result in multiple calls to the constructor of class A, which is undesirable. As there is a single
instance of virtual base class which is shared by multiple classes that inherit from it, hence the
constructor of the base class is only called once by the constructor of concrete class, which in our
case is class D.
If there is any call for initializing the constructor of class A in class B or class C, while creating object
of class D, all such calls will be skipped.
Polymorphism
Polymorphism means having multiple forms of one thing. In inheritance, polymorphism is done, by
method overriding, when both super and sub class have member function with same declaration bu
different definition.
Function Overriding
If we inherit a class into the derived class and provide a definition for one of the base class's function
again inside the derived class, then that function is said to be overridden, and this mechanism is
called Function Overriding
1. Inheritance should be there. Function overriding cannot be done within a class. For this we
require a derived class and a base class.
2. Function that is redefined must have exactly the same declaration in both base and derived
class, that means same name, same return type and same parameter list.
class Base
{
public:
void show()
{
cout << "Base class";
}
};
class Derived:public Base
{
public:
void show()
{
cout << "Derived Class";
}
}
In this example, function show() is overridden in the derived class. Now let us study how these
overridden functions are called in main() function.
int main()
{
Base b; //Base class object
Derived d; //Derived class object
b.show(); //Early Binding Ocuurs
d.show();
}
int main()
{
Base* b; //Base class pointer
Derived d; //Derived class object
b = &d;
b->show(); //Early Binding Occurs
}
Late Binding
In Late Binding function call is resolved at runtime. Hence, now compiler determines the type of
object at runtime, and then binds the function call. Late Binding is also called Dynamic Binding or
Runtime Binding.
int main()
{
Base* b; //Base class pointer
Derived d; //Derived class object
b = &d;
b->show(); //Early Binding Ocuurs
}
int main()
{
Base* b; //Base class pointer
Derived d; //Derived class object
b = &d;
b->show(); //Late Binding Ocuurs
}
class A
{
public:
virtual void show()
{
cout << "Base class\n";
}
};
class B: public A
{
private:
virtual void show()
{
cout << "Derived class\n";
}
};
int main()
{
A *a;
B b;
a = &b;
a -> show();
}
To accomplich late binding, Compiler creates VTABLEs, for each class with virtual function. The
address of virtual functions is inserted into these tables. Whenever an object of such class is created
the compiler secretly inserts a pointer called vpointer, pointing to VTABLE for that object. Hence
when function is called, compiler is able to resovle the call by binding the correct function using the
vpointer.
1. Only the Base class Method's declaration needs the Virtual Keyword, not the definition.
2. If a function is declared as virtual in the base class, it will be virtual in all its derived classes.
3. The address of the virtual Function is placed in the VTABLE and the copiler uses
VPTR(vpointer) to point to the Virtual Function.
Abstract Class
Abstract Class is a class which contains atleast one Pure Virtual function in it. Abstract classes are
used to provide an Interface for its sub classes. Classes inheriting an Abstract Class must provide
definition to the pure virtual function, otherwise they will also become abstract class.
1. Abstract class cannot be instantiated, but pointers and refrences of Abstract class type can be
created.
2. Abstract class can have normal functions and variables along with a pure virtual function.
3. Abstract classes are mainly used for Upcasting, so that its derived classes can use its interface.
4. Classes inheriting an Abstract Class must implement all pure virtual functions, or else they will
become Abstract too.
int main()
{
Base obj; //Compile Time Error
Base *b;
Derived d;
b = &d;
b->show();
}
Output :
Implementation of Virtual Function in Derived class
In the above example Base class is abstract, with pure virtual show() function, hence we cannot
create object of base class.
Pure Virtual functions can be given a small definition in the Abstract class, which you want all the
derived classes to have. Still you cannot create object of Abstract class.
Also, the Pure Virtual function must be defined outside the class definition. If you will define it
inside the class definition, complier will give an error. Inline pure virtual definition is Illegal.
int main()
{
Base *b;
Derived d;
b = &d;
b->show();
}
Output :
Pure Virtual definition
Implementation of Virtual Function in Derived class
Virtual Destructors
Destructors in the Base class can be Virtual. Whenever Upcasting is done, Destructors of the Base
class must be made virtual for proper destrucstion of the object when the program exits.
NOTE : Constructors are never Virtual, only Destructors can be Virtual.
int main()
{
Base* b = new Derived; //Upcasting
delete b;
}
Output :
Base Destructor
In the above example, delete b will only call the Base class destructor, which is undesirable
because, then the object of Derived class remains undestructed, because its destructor is never
called. Which results in memory leak.
int main()
{
Base* b = new Derived; //Upcasting
delete b;
}
Output :
Derived Destructor
Base Destructor
When we have Virtual destructor inside the base class, then first Derived class's destructor is called
and then Base class's destructor is called, which is the desired behaviour.
Pure Virtual Destructors are legal in C++. Also, pure virtual Destructors must be defined, which
is against the pure virtual behaviour.
The only difference between Virtual and Pure Virtual Destructor is, that pure virtual destructor
will make its Base class Abstract, hence you cannot create object of that class.
There is no requirement of implementing pure virtual destructors in the derived classes.
class Base
{
public:
virtual ~Base() = 0; //Pure Virtual Destructor
};
Almost any operator can be overloaded in C++. However there are few operator which can not be
overloaded. Operator that are not overloaded are follows
scope operator - ::
sizeof
member selector - .
member pointer selector - *
ternary operator - ?:
Operator Overloading Syntax
1. Member Function
2. Non-Member Function
3. Friend Function
Operator overloading function can be a member function if the Left operand is an Object of that
class, but if the Left operand is different, then Operator overloading function must be a non-member
function.
Operator overloading function can be made friend function if it needs access to the private and
protected members of class.
#include< iostream.h>
#include< conio.h>
class time
{
int h,m,s;
public:
time()
{
h=0, m=0; s=0;
}
void getTime();
void show()
{
cout<< h<< ":"<< m<< ":"<< s;
}
time operator+(time); //overloading '+' operator
};
time time::operator+(time t1) //operator function
{
time t;
int a,b;
a=s+t1.s;
t.s=a%60;
b=(a/60)+m+t1.m;
t.m=b%60;
t.h=(b/60)+h+t1.h;
t.h=t.h%12;
return t;
}
void time::getTime()
{
cout<<"\n Enter the hour(0-11) ";
cin>>h;
cout<<"\n Enter the minute(0-59) ";
cin>>m;
cout<<"\n Enter the second(0-59) ";
cin>>s;
}
void main()
{
clrscr();
time t1,t2,t3;
cout<<"\n Enter the first time ";
t1.getTime();
cout<<"\n Enter the second time ";
t2.getTime();
t3=t1+t2; //adding of two time object using '+' operator
cout<<"\n First time ";
t1.show();
cout<<"\n Second time ";
t2.show();
cout<<"\n Sum of times ";
t3.show();
getch();
}
You have seen above that << operator is overloaded with ostream class object cout to print
primitive type value output to the screen. Similarly you can overload << operator in your class to print
user-defined type to screen. For example we will overload << in time class to display time object
using cout.
time t1(3,15,48);
cout << t1;
NOTE: When the operator does not modify its operands, the best way to overload the operator is via
friend function.
void main()
{
time tm(3,15,45);
cout << tm;
}
Output
Time is 3 hour : 15 min : 45 sec
Example
class time
{
int hr,min,sec;
public:
time()
{
hr=0, min=0; sec=0;
}
Copy constructor is a special constructor that initializes a new object from an existing object.
time tm(3,15,45); //tm object created and initialized
time t1(tm); //t1 object created and initialized using tm object
STL
Introduction to STL
STL is an acronym for standard template library. It is a set of C++ template classes that provide
generic classes and function that can be used to implement data structures and algorithms. STL is
mainly composed of:
1. Algorithms
2. Containers
3. Iterators
STL provides numerous containers and algorithms which are very useful in completive programming
, for example you can very easily define a linked list in a single statement by using list container of
container library in STL , saving your time and effort.
STL is a generic library , i.e a same container or algorithm can be operated on any data types , you
don’t have to define the same algorithm for different type of elements.
For example , sort algorithm will sort the elements in the given range irrespective of their data type ,
we don’t have to implement different sort algorithm for different datatypes.
Algorithms in STL
STL provide number of algorithms that can be used of any container, irrespective of their type.
Algorithms library contains built in functions that performs complex algorithms on the data structures.
For example: one can reverse a range with reverse() function, sort a range with sort() function,
search in a range with binary_search() and so on.
Algorithm library provides abstraction, i.e you don't necessarily need to know how the the algorithm
works.
Containers in STL
Container library in STL provide containers that are used to create data structures like arrays, linked
list, trees etc.
These container are generic, they can hold elements of any data types, for example: vector can be
used for creating dynamic arrays of char, integer, float and other types.
Iterators in STL
Iterators in STL are used to point to the containers. Iterators actually acts as a bridge between
containers and algorithms.
For example: sort() algorithm have two parameters, starting iterator and ending iterator, now sort()
compare the elements pointed by each of these iterators and arrange them in sorted order, thus it
does not matter what is the type of the container and same sort() can be used on different types of
containers.
Classification of Containers
Containers are classified into four categories :
Sequence containers : Used to implement data structures that are sequential in nature like
arrays(array) and linked list(list).
Associative containers : Used to implement sorted data structures such as map, set etc.
Unordered associative containers : Used to implement unsorted data structures.
Containers adaptors : Used to provide different interface to the sequence containers.
int main ()
{
struct node *list1 = NULL;
}
The above program is only creating a list node, no insertion and deletion functions are defined, to do
that, you will have to write more line of code.
Now lets see how using Container Library simplifies it. When we use list containers to implement
linked list we just have to include the list header file and use list constructor to initialize the list.
#include <iostream>
#include <list>
int main ()
{
list<int> list1;
}
And that's it! we have a list, and not just that, the containers library also give all the different methods
which can be used to perform different operations on list such as insertion, deletion, traversal etc.
Thus you can see that it is incredibly easy to implement data structures by using Container library.
PAIR
NOTE : Although Pair and Tuple are not actually the part of container library but we'll still discuss
them as they are very commonly required in programming competitions and they make certain
things very easy to implement.
SYNTAX of pair is :
pair<T1,T2> pair1, pair2 ;
The above code creates two pairs, namely pair1 and pair2, both having first object of type T1 and
second object of type T2.
Now T1 will be referred as first and T2 will be referred as second member of pair1 and pair2.
int main ()
{
pair<int,int> pair1, pair3; //creats pair of integers
pair<int,string> pair2; // creates pair of an integer an a string
if(pair1 == pair3)
cout<< "Pairs are equal" << endl;
else
cout<< "Pairs are not equal" << endl;
return 0;
}
TUPLE
tuple and pair are very similar in their structure. Just like in pair we can pair two heterogeneous
object, in tuple we can pair three heterogeneous objects.
SYNTAX of a tuple is :
// creates tuple of three object of type T1, T2 and T3
tuple<T1, T2, T3> tuple1;
Some Commonly used Functions
Similar to pair, tuple template has its own member and non-member functions, few of which are
listed below :
int main ()
{
tuple<int, int, int> tuple1; //creates tuple of integers
tuple<int, string, string> tuple2; // creates pair of an integer an 2 string
int id;
string first_name, last_name;
tie(id,first_name,last_name) = pair2;
/* ties id, first_name, last_name to
first, second and third element of tuple2 */
retun 0;
}
ARRAY
Arrays, as we all know, are collection of homogenous objects. array container in STL provides us the
implementation of static array, though it is rarely used in competitive programming as its static in
nature but we'll still discuss array container cause it provides some member functions and non-
member functions which gives it an edge over the array defined classically like, int
array_name[array_size].
SYNTAX of array container :
array <object_type, array_size> array_name;
The above code creates an empty array of object_type with maximum size of array_size. However,
if you want to create an array with elements in it, you can do so by simply using the = operator, here
is an example :
#include <vector>
int main()
{
array<int, 4> odd_numbers = { 2, 4, 6, 8 };
}
The above statement will create an array with 2,4,6,8 as data in the array. Note that initialization with
{} brackets is only possible in c++ 17.
at
This method returns value in the array at the given range. If the given range is greater than the array
size, out_of_range exception is thrown. Here is a code snippet explaining the use of this operator :
#include <iostream>
#include <array>
int main ()
{
array<int,10> array1 = {1,2,3,4,5,6,7,8,9};
[ ] Operator
The use of operator [ ] is same as it was for normal arrays. It returns the value at the given position
in the array. Example : In the above code, statement cout << array1[5]; would print 6 on console
as 6 has index 5 in array1.
front()
This method returns the first element in the array.
back()
This method returns the last element in the array. The point to note here is that if the array is not
completely filled, back() will return the rightmost element in the array.
fill()
This method assigns the given value to every element of the array, example :
#include <array>
int main()
{
array<int,8> myarray;
myarray.fill(1);
}
This will fill the array myarray with value as 1, at all of its 8 available positions.
swap
This method swaps the content of two arrays of same type and same size. It swaps index wise, thus
element of index i of first array will be swapped with the element of index i of the second array, and if
swapping any of the two elements thows an execption, swap() throws exception. Below is an
example to demonstrate its usage :
#include <array>
int main()
{
array<int,8> a = {1,2,3,4,5,6,7,8};
array<int,8> b = {8,7,6,5,4,3,2,1};
empty
This method can be used to check whether the array is empty or not.
Syntax : array_name.empty(), returns true if array is empty else return false.
size
This method returns the number of element present in the array.
max_size
This method returns the maximum size of the array.
begin
This method returns the iterator pointing to the first element of the array. Iterators are just like
pointers and we’ll discuss them later in the lessons, for now you can just think of an iterator like a
pointer to the array.
end
This method returns an iterator pointing to an element next to the last element in the array, for
example the above array has 4 elements and the end() call will return the iterator pointing to the 4th
index of the array.
VECTOR
An array works fine when we have to implement sequential data structures like arrays, except it is
static, i.e. we have to define its maximum size during its initialization and it cannot contain elements
greater than its maximum size. Now suppose, if during the program execution we have to store
elements more than its size, or if we are reading input stream of elements and we do not know the
upper bound of the number of elements, there are high chances of occurrence of index_out_bound
exception or unwanted termination of the program.
We can do one thing, initialize the array with maximum size allowed by the complier, i.e. 10^6
elements per array, but that is highly space consuming approach and there is a wastage of space if
number of elements to be entered are way too less, thus this approach is never used in
programming.
Solution of the above problem is dynamic arrays! They have dynamic size, i.e. their size can change
during runtime. Container library provides vectors to replicate dynamic arrays.
SYNTAX for creating a vector is : vector< object_type > vector_name;
For example :
#include <vector>
int main()
{
std::vector<int> my_vector;
}
Vector being a dynamic array, doesn't needs size during declaration, hence the above code will
create a blank vector. There are many ways to initialize a vector like,
#include <vector>
int main()
{
std::vector<string> v {"Pankaj" , "The" , "Java" ,"Coder"};
}
Note that this type of initialization works only in C++ 11 and above. You can also initialize the vector
based on the range of other vectors, like :
#include <vector>
int main()
{
std::vector<string> v(v1.begin(), v1.end());
}
The above code initialize the vector by elements pointed by iterators returned by v1.begin() and
v2.end(), begin() and end() are the same function we have studied with array, they work same with
vectors.
You can also initialize a vector with one element a certain number of times, like :
#include <vector>
int main()
{
std::vector<string> v(4 , "test");
}
These are me of the ways using which you can initialize your vector, but remember, initializing your
vector using another vector or by using elements directly does not limit its size, its size will always be
dynamic, and more elements can be inserted into the vector, whenever required.
int main()
{
vector<int> v;
v.push_back(1); //insert 1 at the back of v
v.push_back(2); //insert 2 at the back of v
v.push_back(4); //insert 3 at the back of v
insert
insert(itr, element) method inserts the element in vector before the position pointed by iterator itr.
The following illustration will show how insert works :
insert function can be overloaded by third argument, count as well. This count parameter defines
how many times the element is to be inserted before the pointed position.
This method can also be used to insert elements from any other vector in given range, specified by
two iterators, defining starting and ending point of the range.
v.insert(i, v2.begin(), v2.end());
Above code will insert the elements from v2.begin() to v2.end() before index pointed by i.
pop_back
pop_back() is used to remove the last element from the vector. It reduces the size of the vector by
one.
Below is an example :
#include <iostream>
#include <vector>
int main()
{
vector<int> v1 {10,20,30,40};
v1.pop_back();
vector<int>::iterator it;
erase
erase(itr_pos) removes the element pointed by the iterator itr_pos. erase method can also be
overloaded with an extra iterator specifying the end point of the range to be removed, i.e
erase(itr_start, itr_end).
The following code will illustrate erase :
#include <iostream>
#include <vector>
int main()
{
vecto<int>v1 {10,20,30,40};
vector<int>iterator:: it = v.begin();
v.erase(v1.begin(), v1.end() - 2 )
/*removes all the elements except last two */
/* Output : 30 40 */
resize
resize(size_type n, value_type val) method resizes the vector to n elements. If the current size
of the vector is greater than n then the trailing elements are removed from the vector and if the
current size is smaller than n than extra val elements are inserted at the back of the vector.
For example, If the size of the vector is 4 right now, with elements {10, 20, 30, 40} and we use
resize method to resize it to size 5. Then by default a fifth element with value 0 will be inserted in
the vector. We can specify the data to not be zero, by explicitly mentioning it as the val while calling
the resize method.
swap
This method interchanges value of two vectors.
If we have two vectors v1 and v2 and we want to swap the elements inside them, you just need to
call v1.swap(v2), this will swap the values of the two vectors.
clear
This method clears the whole vector, removes all the elements from the vector but do not delete the
vector.
SYNTAX : clear()
For a vector v, v.clear() will clear it, but not delete it.
size
This method returns the size of the vector.
empty
This method returns true if the vector is empty else returns false.
capacity
This method returns the number of elements that can be inserted in the vector based on the memory
allocated to the vector.
at
This method works same in case of vector as it works for array. vector_name.at(i) returns the
element at ith index in the vector vector_name.
front and back
vector_name.front() retuns the element at the front of the vector (i.e. leftmost element). While
vector_name.back() returns the element at the back of the vector (i.e. rightmost element).
LIST
Array and Vector are contiguous containers, i.e they store their data on continuous memory, thus the
insert operation at the middle of vector/array is very costly (in terms of number of operaton and
process time) because we have to shift all the elements, linked list overcome this problem. Linked
list can be implemented by using the list container.
Syntax for creating a new linked list using list template is :
#include <iostream>
#include <list>
int main()
{
std::list<int> l;
}
/* Creates a new empty linked list l */
Similar to vector and array, lists can also be intialised with parameters,
#include <iostream>
#include <list>
int main()
{
std::list<int> l{1,2,3};
}
/* Creates a new linked list l */
Here are some more ways by which we can initialize our list :
#include <iostream>
#include <list>
int main()
{
list<int> myList{1,2,3};
/* creates list with 1,2,3 in it */
list<int> myNewList = 1;
/* create list myNewList of integer
and copies value of 1 into it*/
}
insert(iterator, element) : inserts element in the list before the position pointed by the
iterator.
insert(iterator, count, element) : inserts element in the list before the position pointed by
the iterator, count number of times.
insert(iterator, start_iterator, end_iterator) : insert the element pointed by start_iterator
to the element pointed by end_iterator before the position pointed by iterator
#include <iostream>
#include <list>
int main()
{
list<int> l = {1,2,3,4,5};
list<int>::iterator it = l.begin();
return 0;
}
#include <iostream>
#include <list>
int main()
{
list<int> l{1,2,3,4,5};
l.push_back(6);
l.push_back(7);
/* now the list becomes 1,2,3,4,5,6,7 */
l.push_front(8);
l.push_front(9);
/* now the list becomes 9,8,1,2,3,4,5,6,7 */
int main()
{
list<int> l{1,2,3,4,5};
l.pop_back()();
/* now the list becomes 1,2,3,4 */
l.pop_front()();
/* now the list becomes 2,3,4 */
}
empty
This method returns true if the list is empty else returns false.
size
This method can be used to find the number of elements present in the list.
front and back
front() is used to get the first element of the list from the start while back() is used to get the first
element of the list from the back.
swap
Swaps two list, if there is exception thrown while swapping any element, swap() throws exception.
Both lists which are to be swapped must be of the same type, i.e you can’t swap list of an integer
with list of strings.
reverse
This method can be used to reverse a list completely.
#include <iostream>
#include <list>
int main()
{
list<int> l{1,2,3,4,5};
l.reverse();
/* now the list becomes 5,4,3,2,1 */
}
sort
sort() method sorts the given list. It does not create new sorted list but changes the position of
elements within an existing list to sort it. This method has two variations :
sort() : sorts the elements of the list in ascending order, the element of the list should by
numeric for this function.
sort(compare_function) : This type of sort() is used when we have to alter the method of
sorting. Its very helpful for the elements that are not numeric. We can define how we want to sort
the list elements in compare_funtion. For example, list of strings can be sorted by the length of
the string, it can also be used for sorting in descending order.
#include <iostream>
#include <list>
int main()
{
list<int> list1 = {2,4,5,6,1,3};
list<string> list2 = {"h" , "hhh" , "hh"};
list1.sort();
/* list1 is now 1 2 3 4 5 6 */
list2.sort(compare_function);
/* list2 is now h hh hhh */
}
splice
splice() method transfers the elements from one list to another. There are three versions of splice :
int main ()
{
list<int> list1 = {1,2,3,4};
list<int> list2 = {5,6,7,8};
list<int>::iterator it;
it = list1.begin();
++it; //pointing to second position
list1.splice(it, list2);
/* transfer all elements of list2 at position 2 in list1 */
/* now list1 is 1 5 6 7 8 2 3 4 and list2 is empty */
return 0;
}
merge
Merges two sorted list. It is mandatory that both the list should be sorted first. merge() merges the
two list such that each element is placed at its proper position in the resulting list. Syntax for merge
is list1.merge(list2).
The list that is passed as parameter does not get deleted and the list which calls the merge()
becomes the merged list
#include <iostream>
#include <list>
int main ()
{
list<int> list1 = {1,3,5,7,9};
list<int> list2 = {2,4,6,8,10};
list1.merge(list2);
Notice that keys are arranged in ascending order, its because maps always arrange its keys in
sorted order. In case the keys are of string type, they are sorted lexicographically.
Creating a Map
Maps can easily be created using the following statement :
map<key_type , value_type> map_name;
This will create a map with key of type Key_type and value of type value_type. One thing which is
to remembered is that key of a map and corresponding values are always inserted as a pair, you
cannot insert only key or just a value in a map.
Here is a program that will illustrate creating a map in different ways :
#include <iostream>
#include <map>
map<string,int> map1;
/* creates a map with keys of type character and
values of type integer */
int main ()
{
map<int,string> m{ {1,”nikhilesh”} , {2,”shrikant”} , {3,”ashish”} };
cout << m.at(1) ; // prints value associated with key 1 ,i.e nikhilesh
cout << m.at(2) ; // prints value associated with key 2 ,i.e shrikant
/* note that the parameters in the above at() are the keys not the index */
cout << m[3] ; // prints value associated with key 3 , i.e ashish
m[4] = "doodrah";
/* since there is no key with value 4 in the map,
it insert a key-value pair in map with key=4 and value = “doodrah” */
m.at(5) = "umeshwa";
/* since there is no key with value 5 in the map ,
it throws an exception */
}
empty, size and max_size
empty() returns boolean true if the map is empty, else it returns Boolean false. size() returns
number of entries in the map, an entry consist of a key and a value. max_size() returns the upper
bound of the entries that a map can contain (maximum possible entries) based on the memory
allocated to the map.
insert(pair) : In this variation, a pair of key and value is inserted in the map. The inserted pair
is always inserted at the appropriate position as keys are arranged in sorted order.
insert(start_itr , end_itr) : This variation inserts the entries in range defined by start_itr
and end_itr of another map.
The insert_or_assing() works exactly as insert() except that if the given key is already present in
the map then its value is modified.
#include <iostream>
#include <map>
int main ()
{
map<int,int> m{{1,2} , {2,3} , {3,4} };
map<int,int> new_m;
new_m.insert(i,j);
/* insert all the entries which are pointed
by iterator i to iterator j*/
m.insert( make_pair(3,6));
// do not insert the pair as map m already contain key = 3 */
erase(iterator_itr) : This removes entry from the map pointed by iterator iterator_itr,
reducing the size of map by 1.
erase(start_iterator, end_iterator) : It removes the elements in range specified by the
start_iterator and end_iterator.
The above statement will create a stack named stack_name of type object_type.
int main ()
{
stack<int> s; // creates an empty stack of integer s
}
pop
This method is used to removes single element from the stack. It reduces the size of the stack by 1.
The element removed is always the topmost element of the stack (most recently added element) .
The pop() method does not return anything.
top
This method returns the topmost element of the stack. Note that this method returns the element, not
removes it, unlike pop().
SYNTAX : top()
swap
This method swaps the elements of the two stacks.
#include <iostream>
#include <stack>
using namespace std;
int main ()
{
stack<int> s;
QUEUE
The queue container is used to replicate queue in C++, insertion always takes place at the back of
the queue and deletion is always performed at the front of the queue.
Here is the syntax for defining a queue :
queue< object_type > queue_name;
The above statement will create a queue named queue_name of type object_type.
int main ()
{
queue <int> q; // creates an empty queue of integer q
pop
This method removes single element from the front of the queue and therefore reduces its size by 1.
The element removed is the element that was entered first. the pop() does not return anything.
#include <iostream>
#include <queue>
int main ()
{
queue <int> q; // creates an empty queue of integer q
Swap
Method swap() Swaps the elements of the two queue.
PRIORITY QUEUE
priority_queue is just like a normal queue except the element removed from the queue is always the
greatest among all the elements in the queue, thus this container is usually used to replicate Max
Heap in C++. Elements can be inserted at any order and it have O(log(n)) time complexity for
insertion.
Following is the syntax for creating a priority queue :
priority_queue<int> pq;
int main ()
{
priority_queue<int> pq1;
return 0;
}
pop
This method removes the topmost element from the priority_queue (greatest element) ,reducing the
size of the priority queue by 1.
#include <iostream>>
#include <queue>
using namespace std;
int main ()
{
priority_queue<int> pq1;
return 0;
}
top
This method returns the element at the top of the priority_queue which is the greatest element
present in the queue.
swap
This method swaps the elements of two priority_queue.
DEQUE
Deque is a shorthand for doubly ended queue. Deque allows fast insertion and deletion at both
ends of the queue. Although we can also use vector container for the insertion and deletion at both
of its ends, but insertion and deletion at the front of the array is costlier than at the back, in case of
deque but deque are more complex internally.
Syntax for creating a deque is :
deque< object_type > deque_name;
#include <iostream>
#include <deque>
#include <vector>
int main ()
{
dq.push_back(10);
/* now dq is : 1,5,8,9,3,10 */
dq.push_front(20);
/* now dq is : 20,1,5,8,9,3,10 */
deque<int>::iterator i;
i=dq.begin()+2;
/* i points to 3rd element in dq */
dq.insert(i,15);
/* now dq 20,1,15,5,8,9,3,10 */
int a[]={7,7,7,7};
d1.insert(dq.begin() , a , a+4 );
/* now dq is 7,7,7,7,20,1,15,5,8,9,3,10 */
}
int main ()
{
int a[] = { 1,5,8,9,3,5,6,4 };
deque<int> dq(a,a+8);
/* creates s deque with elements 1,5,8,9,3,5,6,4 */
dq.pop_back();
/* removes an element from the back */
/* now the deque dq is : 1,5,8,9,3,5,6 */
dq.pop_front();
/* now dq is : 1,5,8,9,3,5,6 */
}
Swap
This method can be used to swap elements of two deques.
Defining an iterator
Syntax for defining an iterator is :
container_type <parameter_list>::iterator iterator_name;
int main()
{
vector<int>::iterator i;
/* create an iterator named i to a vector of integers */
vector<string>::iterator j;
/* create an iterator named j to a vector of strings */
list<int>::iterator k;
/* create an iterator named k to a vector of integers */
map<int, int>::iterator l;
/* create an iterator named l to a map of integers */
}
Iterators can be used to traverse the container, and we can de-reference the iterator to get the value
of the element it is pointing to. Here is an example :
#include<iostream>
#include<vector>
int main()
{
vector<int> v(10);
/* creates an vector v : 0,0,0,0,0,0,0,0,0,0 */
vector<int>::iterator i;
return 0;
}
advance
distance
next
prev
begin
end
advance() Operation
It will increment the iterator i by the value of the distance. If the value of distance is negative, then
iterator will be decremented.
SYNTAX : advance(iterator i ,int distance)
#include<iostream>
#include<vector>
int main()
{
vector<int> v(10) ; // create a vector of 10 0's
vector<int>::iterator i; // defines an iterator i to the vector of integers
i = v.begin();
/* i now points to the beginning of the vector v */
advance(i,5);
/* i now points to the fifth element form the
beginning of the vector v */
advance(i,-1);
/* i now points to the fourth element from the
beginning of the vector */
}
distance() Operation
It will return the number of elements or we can say distance between the first and the last iterator.
SYNTAX : distance(iterator first, iterator last)
#include<iostream>
#include<vector>
int main()
{
vector<int> v(10) ; // create a vector of 10 0's
vector<int>::iterator i, j; // defines iterators i,j to the vector of integers
i = v.begin();
/* i now points to the beginning of the vector v */
j = v.end();
/* j now points to the end() of the vector v */
next() Operation
It will return the nth iterator to i, i.e iterator pointing to the nth element from the element pointed by i.
SYNTAX : next(iterator i ,int n)
prev() Operation
It will return the nth predecessor to i, i.e iterator pointing to the nth predecessor element from the
element pointed by i.
SYNTAX : prev(iterator i, int n)
begin() Operation
This method returns an iterator to the start of the given container.
SYNTAX : begin()
end() Operation
This method returns an iterator to the end of the given container.
SYNTAX : end()
if(a[mid] == key) {
return true;
}
else if(a[mid] > key) {
return binary_search(l, mid-1, key, a);
}
else if(a[mid] < key) {
return binary_search(mid+1, r, key, a);
}
}
}
Note that the above function will work only if the array is of intergers and characters.
But in STL we can just use the binary_search() provided by the algorithm library to perform binary
search. It is already defined in the library as :
return binary_search(a, a+a.size())
1. Sorting Algorithms
2. Search algorithms
3. Non modifying algorithms
4. Modifying algorithms
5. Numeric algorithms
6. Minimum and Maximum operations.
sort
is_sorted
partial_sort
sort
This function of the STL, sorts the contents of the given range. There are two version of sort() :
int main()
{
int arr[5] = {1,5,8,4,2};
vector<int> v1;
v1.push_back(8);
v1.push_back(4);
v1.push_back(5);
v1.push_back(1);
/* use of compare_function */
int a2[] = { 4,3,6,5,6,8,4,3,6 };
sort(s,s+4,compare_string);
/* now s is "a","ab","abc","abcde" */
}
partial_sort
partial_sort() sorts first half elements in the given range, the other half elements remain as they
was initially. partial_sort() also has two variations:
partial_sort(start, middle, end ) : sorts the range from start to end in such a way that the
elements before middle are in ascending order and are the smallest elements in the range.
partial_sort(start, middle, end, compare_function) : sorts the range from start to end in
such a way that the elements before middle are sorted with the help of compare_function and
are the smallest elements in the range.
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{
int a[] = {9,8,7,6,5,4,3,2,1};
is_sorted
This function of the STL, returns true if the given range is sorted. There are two version of
is_sorted() :
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{
int a[5] = {1,5,8,4,2};
cout<<is_sorted(a, a+5);
/* prints 0 , Boolean false */
vector<int> v1;
v1.push_back(8);
v1.push_back(4);
v1.push_back(5);
v1.push_back(1);
binary_search(first, last, value) : this version returns true if there is an element present,
satisfying the condition (!(a < value) &&!(value < a)) in the given range, i.e from first to last, in
other words, operator(<) is used to check the equality of the two elements.
binary_search(first, last, value, compare_function) : this version return true if there is an
element present in the given range, i.e from first to the last.
Note that first and last are iterators and the element pointed by last is excluded from the search.
Here we don't have to first sort element container, binary_search() will do all the work for us, we just
have to give a range and a value which is to searched.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main ()
{
int inputs[] = {7,8,4,1,6,5,9,4};
vector v(inputs, inputs+8);
cout<compare_string_by_length);
/* search for the string in s which have same length as of "nicky" */
}
equal_range
equal_range() returns a pair of iterators where the iterators represent the sub range of
elements in the given range which are equal to the given value or satisfy the
compare_function. The given range should be already sorted. There are two variation of
equal_range :
equal_range(first, last, value) : returns a pair of iterators representing the sub range of
(first,last) which have elements equal to value.
equal_range(first, last, value, compare_function) : returns a pair of iterators
representing the sub range of (first,last) which have elements satisfying
compare_function with value.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main ()
{
int input[] = {1,1,1,2,2,2,3,3,6,7,7,7,7,7,8,9};
vector v(input, input+16);
upper_bound
upper_bound() returns an iterator to the elements in the given range which does not compare greater
than the given value. The range given should be already sorted for upper_bound() to work properly.
In other words it returns an iterator to the upper bound of the given element in the given sorted
range.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main ()
{
int input[] = {1,2,2,3,4,4,5,6,7,8,10,45};
vector<int> v(input, input+12);
int main ()
{
int input[] = {1,2,2,3,4,4,5,6,7,8,10,45};
vector<int> v(input,input+12);
count
equal
mismatch
search
search_n
count
count() returns the number of elements in the given range that are equal to given value. Syntax for
count is:
count(first ,last ,value) : This will return number of the element in range defined by iterators first
and last ( excluded ) which are equal ( == ) the value .
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main ()
{
int values[] = {5,1,6,9,10,1,12,5,5,5,1,8,9,7,46};
return 0;
}
equal
equal() compares the elements in two ranges, if all the elements in one range compares equal to
their corresponding elements in other range, Boolean true is returned, else Boolean false is
returned. There are two variation of it :
equal(first1, last1, first2) : This function compare for the equality of elements in the range
pointed by first1 and last1(excluded) to the range with starting position first2. If all elements are
equal , true is returned else false.
equal(first1 ,last1 ,first2 ,cmp_function) : Here cmp_function is used to decide how to
check the equality of two elements, it is useful for non-numeric elements like strings and objects.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main()
{
int inputs1[] = { 1,2,3,4,5,6,7,8};
int inputs2[] = { -1,2,1,2,3,4,6,7,8,9};
mismatch
This method returns a pair of iterator, where first iterator of the pair points to the element in first
container and second iterator points to the element in the second container where mismatch has
occurred. There are two variations of mismatch().
mismatch(first1, last1, first2) : Here first1 and last1 are the iterators to the first container
specifying the range and first2 is the iterator to the second container specifying the position
where to start the comparison. The elements are by default checked for equality == and the pair
of iterator is returned giving the position of elements where mismatch has occurred.
mismatch(first1, last1, first2, compare_function) : This version works same as the above
one except compare_function is used to check whether elements are to be consider equal or
not.
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{
int inputs1[] = {1,2,3,4,5,6,7,8};
int inputs1[] = {-1,2,1,2,3,4,6,7,8,9};
search
This function is used to perform searches for a given sequence in a given range. There are two
variations of the search():
search(first1 ,last1 ,first2 ,last2) : This function searches for the sequence defined by
first2 and last2 in the range first1 and last1(where last1 is excluded). If there is a match an
iterator to the first element of the sequence in the range [first1,last1] is returned, else iterator to
last1 is returned.
search(first1 ,last1 ,first2 ,last2 ,cmp_functions) : Here cmp_function is used to
decide how to check the equality of two elements, it is useful for non-numeric elements like
strings and objects.
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{
int inputs1[] = { 1,2,3,4,5,6,7,8};
int inputs2[] = { 2,3,4};
vector<int>::iterator i ,j;
search_n
This method searches in a given range for a sequence of a count value. There are two variations of
the search():
search(first1, last1, count, value) : This method searches for a sequence of count and
value in the range defined by iterators first1 and last1(last1 is excluded). If there is a match an
iterator to the first element of the sequence in the range [first1,last1] is returned, else iterator to
last1 is returned.
search(first1, last1, count, value, cmp_functions) : Here cmp_function is used to decide
how to check the equality of two elements, it is useful for non-numeric elements like strings and
objects.
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{
int inputs1[] = {1,2,3,4,4,4,8,5,6,7,8};
int main ()
{
vector<int> v1,v2;
v1.push(2);
v1.push(4);
v1.push(6);
v1.push(8);
v1.push(10);
/* v2 is now 2,4,6,8,10 */
}
copy_n method
This function copies the first n elements from the position defined by iterators first into the range
starting by the iterator first2.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main ()
{
int values[] = {1,2,3,4,5,6,7,8,9};
vector<int> v1(values, values+9), v2;
int main ()
{
vector<int> v1(10); // v1 is now 0,0,0,0,0,0,0,0,0,0
fill_n method
This method assingns the first n elements a given value from the position defined by iterator first.
Syntax for fill_n is fill_n(iterator first, iterator last, int value)
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main ()
{
int values[] = {1,2,3,4,5,6,7,8,9};
vector<int> v1(values, values+9);
fill_n(v1.begin(), 5 ,10);
/* v1 is now 10,10,10,10,10,6,7,8,9 */
}
move
This method moves the elements form the current container and return its rvalue reference. Syntax
for move is move(element). move() is available in C++ 11 and above.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int main ()
{
string a = "nicky";
string b = "Vicky";
vector<string> name;
transform
transform applies a unary/binary operation on a given range and copies the result into the range
starting from iterator res. There are two version of transform() which differ by the type of operations
performed on the elements.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int unaryoperation (int a)
{
return a*2;
}
int main()
{
vector<int> v1;
vector<int> v2;
vector<int> res1;
vector<int> res2;
/* v2 : 1,2,3,4,5,6,7,8,9 */
/* v1 : 10,20,30,40,50,60,70,80,90 */
res2.resize(10);
generate_n method
This method assigns first n elements in the given range to the value returned by the successive call
to function generate_element. Syntax for generate is generate(iterator first, int n,
generator_function generate_element).
#include <iostream>
#include <algorithm>
#include <vector>
#include <time.h>
#include <cstdlib>
int generate_random()
{
return rand()%10;
}
int main()
{
srand(time(NULL));
vector<int> v1 , v2;
v1.resize(10);
v2.resize(10);
generate(v1.begin(), v1.end(), generate_random) ;
generate_n(v2.begin(), 5, generate_random);
swap Method
This method swaps the elements of two container of same type.
#include <iostream>
#include <utility>
#include <vector>
int main ()
{
int a = 6;
int b = 9;
swap(a,b);
/* a = 9 , b=6 */
vector<int> v, c;
for(int j=0; j < 10; j++)
{
v.push_back(j);
c.push_back(j+1);
}
swap(v,c);
cout<<endl;
swap_ranges
swap_ranges(iterator first1, iterato last1, iterato first2) : It swaps the elements in the
range [first1, last1] with the elements present in the range starting from first2.
#include <iostream>
#include <utility>
#include <vector>
int main ()
{
vector<int> v, c;
for(int j=0; j < 10; j++)
{
v.push_back(j);
c.push_back(j+1);
}
cout<<endl;
reverse
reverse(iterator first, iterator last) is used to reverse the order of the elements in the range
[first, last].
#include <iostream>
#include <algorithm>
#include <vector>
int main ()
{
int a[] = {1,5,4,9,8,6,1,3,5,4};
reverse(a, a+10);
reverse(a, a+5);
reverse(v.begin(), v.end());
reverse_copy
This method copies the elements in the given range in the reverse order. It does not change the
order of the original container. Syntax for reverse_copy is reverse_copy(iterator first ,iterator
last ,iterator res), copies the elements in the range [first, last] in the reverse order to the range
starting by iterator res.
#include <iostream>
#include <algorithm>
#include <vector>
int main()
{
int values[] = {1,4,8,9,5,6,2,7,4,1};
vector<int> v2;
/* now v2 is : 1,4,7,2,6,5,9,8,4,1 */
}
rotate
This method is used to rotate(iterator first, iterator middle, iterator last) the elements
present in the given range [first,last] such that the element pointed by the middle iterator becomes
first element.
#include <iostream>
#include <algorithm>
#include <vector>
int main ()
{
int a[] = {1,5,9,8,4,6,9,2};
vector<int> v(a,a+8);
rotate(a,a+4,a+8);
/* rotate a such that a[4] is now the first element of array a */
/* now a is : 4,6,9,2,1,5,9,8 */
unique
This method removes the consecutive duplicate elements from the given range. It have two
variations. It returns an iterator to the position which is next to the last element of the new range.
resize() can be used for adjusting the size of the container after unique().
unique(iterator first, iterator last) : It removes all the consecutive duplicate elements
except the first one in the range [first,last]. Operator ==, is used to check if the elemets are
duplicate or not.
unique(iterator first, iterator last, bool compare_function) : In this version, we use
compare_function to check if the elememts are duplicate of not.
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
int main ()
{
int values[] = {10,5,5,5,9,6,6,4,4};
vector<int> v (values,values+9) , v4;
vector<int>::iterator it;
it = unique(v.begin(), v.end());
/* vector v is now : 10,5,9,6,4,-,-,-,- */
v.resize(distance(v.begin(),it));
/* resize the vector by the size returned by distance function,
which returns the distance between the two iterators */
/* using compare_function */
unique_copy
This method copies the unique elements from the range [first,last] and returns the iterator to the
position next to the last element in the new range. It have two variations. It returns an iterator to the
position which is next to the last element of the new range. resize() can be used for adjusting the
size of the container after unique().
#include <iostream>
#include <algorithm>
#include <vector>
int main ()
{
int values[] = {10,5,5,5,9,6,6,4,4};
vector<int> v (values,values+9);
vector<int> v2;
v2.resize(v.size());
vector<int>::iterator it;
it = unique(v.begin(), v.end());
/* vector v2 is now : 10,5,9,6,4,-,-,-,- */
v.resize(distance(v.begin(), it));
/* resize the vector by the size returned by distance function,
which returns the distance between the two iterators */
/* using compare_function */
vector<int> v3(values,values+9),v4;
v4.resize(v3.size());
return 0;
}
Numeric Algorithms in STL
Following are some Numeric algorithms in Standard Template library that we will be covering :
iota Method
accumulate Method
partial_sum Method
iota Method
This method assigns all the successive elements in range [first, last] as an incremented value of the
element itself. It is available in c++ 11 and above. Its syntax is iota(iterator first, iterator
last, int value ).
#include<iostream>
#include<numeric>
#include<vector>
int main()
{
vector<int> v(10);
/* now vector v is : 0,0,0,0,0,0,0,0,0,0 */
iota(v.begin(), v.end(), 10 );
accumulate Method
This method performs the operation op on all the element in the range [first, last] and stores the
result into the container result. There are two variations of accumulate, in the first one no binary
operator is defined in the function call, so by default addition is performed, otherwise binary
operator op is performed.
Following is the syntax of accumulate method with binary operator op :
accumulate(iterator first, iterator last, object_type result, binaryoperator op)
Following is an example to demonstrate the usage of accumulate :
#include<iostream>
#include<numeric>
#include<vector>
int main()
{
vector<int> v;
int result;
/* now result = 45 */
/* applies myoperator on all the elements in the range v.begin() and v.end() and store them in
result */
/* now result = 9! */
}
partial_sum Method
This method assigns every element in the range starting from iterator result of the operation op on
the successive range in [first, last]. Here binary_operation can be omitted, if there is no binary
operator specified, addition is done by default.
The syntax of partial_sum is :
partial_sum(iterator first, iterator last, iterator result, binary_operation op)
Following is an example to demonstrate the usage of partial_sum :
#include<iostream>
#include<numeric>
#include<vector>
int main()
{
int a[] = {1,2,3,4,5};
vector<int> v (a,a+5);
vector<int> v2;
/* vector v is 1,2,3,4,5 */
v2.resize(v.size());
/* now v2 is : 1,3,6,10,15 */
/* sum of the successive range in v.begin() and v.end() */
/* now v2 is : 1,2,6,24,120 */
}
Minimum and Maximum operations in STL
Following are the functions that we will be covering :
max Method
max_element Method
min Method
min_element Method
minmax Method
minmax_element Method
lixicographically_compare Method
next_permutation Method
prev_permutation Method
int main()
{
int x=4, y=5;
int main()
{
int values[] = { 1,5,4,9,8,10,6,5,1};
vector<int> v(values,values+9);
It compares the ranges [first1,last1] and [first2,last2] and returns true if the first range is
lexicographically smaller than the later one.
A custom compare function can be defined and used when we want to define how the elements are
to be compared. Following is the syntax of that variant of this method.
lexicographical_compare(iterator first1, iterator last1, iterator first2, iterator last2, bool
compare_function)
int main()
{
char s[] = "nkvaio";
char x[] = "xyzabc";
cout >> lexicographical_compare(s, s+6, x, x+6, myoperator);
/* prints 0 , Boolean false , since a[4] is not less than b[4] */
}
MinMax and Permutation operations in STL
Following are the functions that we will be covering, as we have already covered the other methods
of Minimum and Maximum Operations in STL in the previous lesson.
minmax Method
minmax_element Method
next_permutation Method
prev_permutation Method
int main()
{
pair<int,int> p;
p = minmax(2,3);
/* now p.first = 2 ( smaller element )
And p.second = 3 ( larger element ) */
pair<string,string> p2;
p2 = minmax("abcd" , "abce");
/* p2.first = "abcd" ( lexicographically smaller string )
And p2.second = "abce" (lexicographically larger string ) */
p = minmax(2,2);
/* p.first = p.second = 2 , */
p = minmax({2,6,5,4,9,8});
/* now p.first = 2 ( smaller element )
And p.second = 9 ( larger element ) */
}
int main ()
{
array<int,7> foo {3,7,2,9,5,8,6};
// print result:
cout << "min is " << *result.first;
cout << "max is " << *result.second;
return 0;
}
int main ()
{
char s[] = "abcd";
next_permutation(s, s+4);
cout << s >> endl;
/* prints "abdc" */
rev_permutation(s, s+4);
cout << s >> endl;
/* prints "dcba" */
int a[] = {1,2,3,4};
next_permutation(a, a+4);
/* now a is 1,2,4,3 */
next_permutation(v.begin(), v.end() );
/* now v is : 1,3,2,4 */
prev_permutation(a, a+4);
/* now a is 4,3,2,1 */
return 0;
}
http://www.bogotobogo.com/cplusplus/cpptut.php
1. What is a class?
o A class is a way of encapsulating data, defining abstract data types along
with initialization conditions and operations allowed on that data; a way of
hiding the implementation (hiding the guts & exposing the skin); a way of
sharing behavior and characteristics
2. What are the differences between a C struct and a C++ struct?
o A C struct is just a way of combining data together; it only has characteristics
(the data) and does not include behavior (functions may use the structure but
are not tied up to it)
o Typedefed names are not automatically generated for C structure tags; e.g.,:
o // a C struct
o struct my_struct {
o int someInt;
o char* someString;
o };
o
o // you declare a variable of type my_struct in C
o struct my_struct someStructure;
o
o // in C you have to typedef the name to easily
o // declare the variable
o typedef my_struct MyStruct;
o MyStruct someOtherStuct;
o
o // a C++ struct
o struct MyCppStruct {
o int someInt;
o char* someString;
o };
o
o // you declare a variable of type MyCppStruct in C++
o MyCppStruct someCppStruct;
o // as you can see the name is automatically typedefed
o But what’s more important is that a C struct does not provide enablement for
OOP concepts like encapsulation or polymorphism. Also “C structs can’t
have static members or member functions”, [bmerry]. A C++ struct is
actually a class, the difference being that the default member and base class
access specifiers are different: class defaults to private whereas struct
defaults to public.
3. What does the keyword const mean and what are its advantages over #define?
o In short and by far not complete, const means “read-only”! A named
constant (declared with const) it’s like a normal variable, except that its value
cannot be changed. Any data type, user-defined or built-in, may be defined as
a const, e.g.,:
o // myInt is a constant (read-only) integer
o const int myInt = 26;
o
o // same as the above (just to illustrate const is
o // right and also left associative)
o int const myInt = 26;
o
o // a pointer to a constant instance of custom
o // type MyClass
o const MyClass* myObject = new MyObject();
o
o // a constant pointer to an instance of custom
o // type MyClass
o MyClass* const myObject = new MyObject();
o
o // myInt is a constant pointer to a constant integer
o const int someInt = 26;
o const int* const myInt = &someInt;
o #define is error prone as it is not enforced by the compiler like const is. It
merely declares a substitution that the preprocessor will perform without any
checks; that is const ensures the correct type is used, whereas #define does
not. “Defines” are harder to debug as they are not placed in the symbol table.
o A constant has a scope in C++, just like a regular variable, as opposed to
“defined” names that are globally available and may clash. A constant must
also be defined at the point of declaration (must have a value) whereas
“defines” can be “empty.”
o Code that uses const is inherently protected by the compiler against
inadvertent changes: e.g., to a class’ internal state (const member variables
cannot be altered, const member functions do not alter the class state); to
parameters being used in methods (const arguments do not have their
values changed within methods) [sql_lall]. A named constant is also subject
for compiler optimizations.
o In conclusion, you will have fewer bugs and headaches by preferring const to
#define.
4. Can you explain the private, public and protected access specifiers?
o public: member variables and methods with this access specifier can be
directly accessed from outside the class
o private: member variables and methods with this access specifier cannot be
directly accessed from outside the class
o protected: member variables and methods with this access specifier cannot
be directly accessed from outside the class with the exception of child classes
o These access specifiers are also used in inheritance (that’s a whole other
story, see next question). You can inherit publicly, privately or protected
(though I must confess, I cannot see the benefits of the latter).
5. Could you explain public and private inheritance?[kyky, sql_lall]
o Public inheritance is the “default” inheritance mechanism in C++ and it is
realized by specifying the public keyword before the base class
o class B : public A
o {
o };
o Private inheritance is realized by specifying the private keyword before the
base class or omitting it completely, as private is the default specifier in C++
o class B : private A
o {
o };
o or
o class B : A
o {
o };
o The public keyword in the inheritance syntax means that the
publicly/protected/privately accessible members inherited from the base class
stay public/protected/private in the derived class; in other words, the
members maintain their access specifiers. The private keyword in the
inheritance syntax means that all the base class members, regardless of their
access specifiers, become private in the derived class; in other words, private
inheritance degrades the access of the base class’ members – you won’t be
able to access public members of the base class through the derived one (in
other languages, e.g., Java, the compiler won’t let you do such a thing).
o From the relationship between the base and derived class point of view,
o class B : public A {}; B "is a" A but class B : private A {};
Private inheritance, on the other hand, class B : private A {};, does not create
subtypes making the base type inaccessible and is a form of object
composition. The following illustrates that:
class A
{
public:
A();
~A();
void doSomething();
};
void A :: doSomething()
{
}
class B : private A
{
public:
B();
~B();
};
B* beePointer = new B();
8. How can you force the compiler not to generate the above mentioned
methods?
o Declare and define them yourself – the ones that make sense in your class’
context. The default no-parameters constructor will not be generated if the
class has at least one constructor with parameters declared and defined.
o Declare them private – disallow calls from the outside of the class and DO
NOT define them (do not provide method bodies for them) – disallow calls
from member and friend functions; such a call will generate a linker error.
9. What is a constructor initialization list?
o A special initialization point in a constructor of a class (initially developed for
use in inheritance).
o Occurs only in the definition of the constructor and is a list of constructor calls
separated by commas.
o The initialization the constructor initialization list performs occurs before any
of the constructor’s code is executed – very important point, as you’ll have
access to fully constructed member variables in the constructor!
o For example:
o // a simple base class just for illustration purposes
o class SimpleBase
o {
o public:
o SimpleBase(string&);
o ~SimpleBase();
o private:
o string& m_name;
o };
o
o // example of initializer list with a call to the
o // data member constructor
o SimpleBase :: SimpleBase(string& name) : m_name(name)
o {
o
o }
o
o // a class publicly derived from SimpleBase just for
o // illustration purposes
o class MoreComplex : public SimpleBase
o {
o public:
o MoreComplex(string&, vector<int>*, long);
o ~MoreComplex();
o private:
o vector<int>* m_data;
o const long m_counter;
o };
o
o
o // example of initializer list with calls to the base
o // class constructor and data member constructor;
o // you can see that built-in types can also be
o // constructed here
o MoreComplex :: MoreComplex(string &name,
o vector<int>* someData, long counter) :
o SimpleBase(name), m_data(someData),
o m_counter(counter)
o {
o
o }
o As you saw in the above example, built-in types can also be constructed as
part of the constructor initialization list.
o Of course you do not have to use the initialization list all the time (see the
next question for situations that absolutely require an initialization list) and
there are situations that are not suitable for that: e.g., you have to test one of
the constructor’s arguments before assigning it to your internal member
variable and throw if not appropriate.
o It is recommended that the initialization list has a consistent form: first the call
to the base class(es) constructor(s), and then calls to constructors of data
members in the order they were specified in the class’ declaration . Note that
this is just a matter of coding style: you declare your member variables in a
certain order and it will look good and consistent to initialize them in the same
order in the initialization list.
10. When “must” you use a constructor initialization list?
o Constant and reference data members of a class may only be initialized,
never assigned, so you must use a constructor initialization list to properly
construct (initialize) those members.
o In inheritance, when the base class does not have a default constructor or
you want to change a default argument in a default constructor, you have to
explicitly call the base class’ constructor in the initialization list.
o For reasons of correctness – any calls you make to member functions of sub-
objects (used in composition) go to initialized objects.
o For reasons of efficiency. Looking at the previous question example we could
rewrite the SimpleBase constructor as follows:
o SimpleBase :: SimpleBase(string &name)
o {
o m_name = name;
o }
The above will generate a call to the default string constructor to construct the class
member m_name and then the assignment operator of the string class to assign the
name argument to the m_name member. So you will end up with two calls before the
data member m_name is fully constructed and initialized.
SimpleBase :: SimpleBase(string &name) : m_name(name)
{
}
The above will only generate a single call, which is to the copy constructor of the
string class, thus being more efficient.
That’s it for the first part of this installment. Stay tuned for the second one, as we’re going to
go deeper into the language features. Good luck on those interviews!
“A virtual function must be defined for the class in which it is first declared …”
[Stroustrup]. The redefinition of a virtual function in a derived class is called
overriding (complete rewrite) or augmentation (rewrite but with a call to the base
class function)
What will happen in our rather lengthy example? Everything seems OK and most of
the available C++ compilers will not complain about anything (*). Nevertheless there
is something pretty wrong here. The C++ standard is clear on this topic: when you
want to delete a derived class object through a base class pointer and the
destructor of the base class is not virtual the result is undefined. That means
you’re on your own from there and the compiler won’t help you! What is the most
often behavior in such situations is that the derived class’ destructor is never called
and parts of your derived object are left undestroyed. In the example above you will
leave behind a memory leak, the m_charCodes member will not be destroyed because
the destructor ~Derived() will not be called
o A thing to notice is that declaring all destructors virtual is also pretty inefficient and
not advisable. That makes sense (declaring the destructor virtual) only if your class is
supposed to be part of a hierarchy as a base class, otherwise you’ll just waste memory
with the class’ vtable generated only for the destructor. So declare a virtual destructor
in a class “if and only if that class is part of a class hierarchy, containing at least
one virtual function. In other words, it is not necessary for the class itself to have
that virtual function – it is sufficient for one of its descendents to have
one.”[kyky]
3. How do you implement something along the lines of Java interfaces in C++?[kyky]
o C++ as a language does not support the concept of “interfaces” (as opposed to other
languages like Java or D for example), but it achieves something similar through
Abstract Classes
o You obtain an abstract class in C++ by declaring at least one pure virtual function
in that class. A virtual function is transformed in a pure virtual with the help of the
initializer “= 0″. A pure virtual function does not need a definition. An abstract class
cannot be instantiated but only used as a base in a hierarchy
o class MySillyAbstract
o {
o public:
o // just declared not defined
o virtual void beSilly() = 0;
o };
A derivation from an abstract class must implement all the pure virtuals, otherwise it
transforms itself into an abstract class
o You can obtain an “interface” in C++ by declaring an abstract class with all the
functions pure virtual functions and public and no member variables – only behavior
and no data
o class IOInterface
o {
o public:
o virtual int open(int opt) = 0;
o virtual int close(int opt) = 0;
o virtual int read(char* p, int n) = 0;
o virtual int write(const char* p, int n) = 0;
o };
[adapted after an example found in Stroustup The C++ Programming Language 3rd
Edition]
In this way you can specify and manipulate a variety of IO devices through the
interface.
4. Could you point out some differences between pointers and references?
o A reference must always be initialized because the object it refers to already exists; a
pointer can be left uninitialized (though is not recommended)
o There’s no such thing a s a “NULL reference” because a reference must always refer
to some object, so the “no object” concept makes no sense; pointers, as we all know,
can be NULL
o References can be more efficient, because there’s no need to test the validity of a
reference before using it (see above comment); pointers most often have to be tested
against NULL to ensure there are valid objects behind them
o Pointers may be reassigned to point to different objects (except constant pointers, of
course), but references cannot be (references are “like” constant pointers that are
automatically dereferenced by the compiler)
o References are tied to someone else’s storage (memory) while pointers have their
own storage they account for
o One would use the dot operator “.” to access members of references to objects,
however to access members of pointers to objects one uses the arrow “->”[sql_lall]
5. When would you use a reference?
o You should use a reference when you certainly know you have something to refer to,
when you never want to refer to anything else and when implementing operators
whose syntactic requirements make the use of pointers undesirable; in all other cases,
“stick with pointers”
o Do not use references just to reduce typing. That (and that being the sole reason) is
not an appropriate usage of the reference concept in C++; using references having in
mind just the reason of reduced typing would lead you to a “reference spree” – it
must be clear in one’s mind when to use references and when to use pointers;
overusing any of the two is an inefficient path
6. Can you point out some differences between new & malloc?
o “new” is an operator built-in into the C++ language, “malloc” is a function of the C
standard library
o “new” is aware of constructors/destructors, “malloc” is not; e.g. :
o string* array1 = static_cast<string*>(malloc(10 * sizeof(string)));
o free(array1);
array1 in the above example points to enough memory to hold 10 strings but no
objects have been constructed and there’s no easy and clean (proper) way from OO
point of view to initialize them (see the question about placement new – in most day
to day programming tasks there’s no need to use such techniques). The call to free()
deallocates the memory but does not destroy the objects (supposing you managed to
initialize them).
string* array2 = new string[10];
delete[] array2;
on the other hand array2 points to 10 fully constructed objects (they have not been
properly initialized but they are constructed), because “new” allocates memory and
also calls the string default constructor for each object. The call to the delete
operator deallocates the memory and also destroys the objects
o You got to remember to always use free() to release memory allocated with malloc()
and delete (or the array correspondent delete[]) to release memory allocated with
new (or the array correspondent new[])
7. What are the differences between “operator new” and the “new” operator?
o “new” is an operator built into the language and it’s meaning cannot be changed;
“operator new” is a function and manages how the “new” operator allocates
memory its signature being: void* operator new(size_t size)
o The “new” operator is allowed to call a constructor, because new has 2 major steps in
achieving its goals : in step 1 it allocates enough memory using “operator new” and
then in step 2 calls the constructor(s) to construct the object(s) in the memory that
was allocated
o “operator new” can be overridden meaning that you can change the way the “new”
operator allocates memory, that is the mechanism, but not the way the “new”
operator behaves, that is it’s policy(semantics) , because what “new” does is fixed by
the language
8. What is “placement new”?
o A special form of constructing an object in a given allocated zone of memory
o The caller already knows what the pointer to the memory should be, because it knows
where is supposed to be placed. “placement new” returns the pointer that’s passed
into it
o Usage of “placement new” implies an explicit call to the object’s destructor when
the object is to be deleted, because the memory was allocated/obtained by other
means than the standard “new” operator allocation
o E.g. :
o // supposing a "buffer" of memory large enough for
o // the object we want to construct was
o // previously allocated using malloc
o MyClass* myObject = new (buffer) MyClass(string& name);
o
o
o // !!ERROR
o delete myObject;
o // the correct way is
o myObject->~MyClass();
o // then the "buffer" must also be properly
o // deallocated
o free(buffer);
9. What is a “virtual constructor”?[kyky]
o There is no such thing as a virtual constructor in C++ simply because you need to
know the exact type of the object you want to create and virtual represent the exact
opposite concept (***)
o But using an indirect way to create objects represents what is known as “Virtual
Constructor Idiom”. For example you could implement a clone() function as an
indirect copy constructor or a create() member function as an indirect default
constructor (C++ FAQ Lite)
o The GoF calls a variant of this idiom the Factory Method Pattern – “define an
interface for creating an object, but let subclasses decide which class to instantiate.
Factory Method lets a class defer instantiation to subclasses”. A concrete example
will speak for itself:
// Product
class Page
{
};
// ConcreteProduct
class SkillsPage : public Page
{
};
// ConcreteProduct
class ExperiencePage : public Page
{
};
// ConcreteProduct
class IntroductionPage : public Page
{
};
// ConcreteProduct
class TableOfContentsPage : public Page
{
};
// Creator
class Document
{
// Constructor calls abstract Factory method
public:
Document();
// Factory Method
virtual void CreatePages() { };
protected:
std::list<Page*> thePageList;
};
Document :: Document()
{
CreatePages();
};
// ConcreteCreator
class Resume : public Document
{
public:
// Factory Method implementation
void CreatePages();
};
// ConcreteCreator
class Report : public Document
{
public:
// Factory Method implementation
void CreatePages();
};
return 0;
}
That was it, folks! I hope that even if those questions did not pose any challenges, you still had fun
doing/reading this quiz and refreshing your memory on some aspects of the C++ language. Good
luck on those interviews!
Notes
(*) bmerry suggested that my claim is not accurate but I’ve tested the example on Windows XP:
Visual Studio 2005 Professional Edition (the evaluation one that you can get from the Microsoft site
) did not warn, not even after setting the warnings level to Level 4 (Level 3 is the default one);
Mingw compiler based on GCC (that comes with the Bloodshed DevCpp version 4.9.9.2) also did
not warn (the compiler settings from within the IDE are minimalist; tried to pass -pedantic and -
Wextra to the compiler command line but still no success); Digital Mars C++ compiler (dmc) also
did not warn with all warnings turned on; Code Warrior Professional Edition 9 does not warn also
(this is pretty old, but Metrowerks compilers were renowned for the robustness and standard
conformance). So, unless you start digging through the documentation of those compilers to find that
right command line switch or start writing the right code, you’re in the harms way at least with the
“out of the box” installations of these compilers.
(**) The compiler does all the magic: first, for each class that contains virtual functions (base and
derived), the compiler creates a static table called the VTABLE. Each virtual function will have a
corresponding entry in that table (a function pointer); for the derived classes the entries will contain
the overridden virtual functions’ pointers. For each base class (it’s not static, each object will have
it) the compiler adds a hidden pointer called the VPTR, that will be initialized to point to the
beginning of the VTABLE – in the derived classes the (same) VPTR will be initialized to point to
the beginning of the derived class’ VTABLE. So when “you make a virtual function call through a
base class pointer (that is, when you make a polymorphic call), the compiler quietly inserts code to
fetch the VPTR and look up the function address in the VTABLE, thus calling the correct function”.
This might seem overly complicated but on a typical machine it does not take much space and it’s
very, very fast as a smart man said once “fetch, fetch call”.
#include <iostream>
using namespace std;
class Fred {
public:
void f(int i) throw();
void g(int i) throw();
void h(int i) throw();
};
typedef void(Fred::*FredMemberPtr)(int);