Sei sulla pagina 1di 176

Contents

Difference between "C structure" and "C++ structure" ........................................................................... 4


What is difference between C and C++ .................................................................................................... 5
Is it possible to get the source code back from binary file ..................................................................... 16
What are virtual functions and what is its use ....................................................................................... 16
Introduction ......................................................................................................................................... 19
UPCASTING ...................................................................................................................................... 23
Example of upcasting usage ................................................................................................................ 24
Memory layout .................................................................................................................................... 25
DOWNCASTING ............................................................................................................................... 25
Dynamic Cast ...................................................................................................................................... 26
Introduction to Classes and Objects ................................................................................................... 27
Types of Member Functions ............................................................................................................... 28
Self-Inputs:.......................................................................................................................................... 33
Inner Join................................................................................................................................................. 34
Example of Inner Join .......................................................................................................................... 34
Outer Join ................................................................................................................................................ 35
Left Outer Join..................................................................................................................................... 36
Right Outer Join .................................................................................................................................. 37
Right Join Example .............................................................................................................................. 38
Full Outer Join ..................................................................................................................................... 39
Upcasting in C++.................................................................................................................................. 41
Polymorphism ..................................................................................................................................... 44
Virtual Functions ................................................................................................................................. 47
Abstract Class ...................................................................................................................................... 52
Virtual Destructors .............................................................................................................................. 54
Operator Overloading ......................................................................................................................... 57
Operator Overloading Examples ......................................................................................................... 58
STL ............................................................................................................................................................... 64
Introduction to STL.................................................................................................................................. 64
What are Containers? ......................................................................................................................... 66
Classification of Containers ................................................................................................................. 66
PAIR ..................................................................................................................................................... 67
Program demonstrating PAIR Template ............................................................................................. 68
TUPLE .................................................................................................................................................. 69
Program demonstrating Tuple template ............................................................................................ 70
ARRAY.................................................................................................................................................. 71
Member Functions of array template................................................................................................. 72
VECTOR ............................................................................................................................................... 75
Member Functions of Vector .............................................................................................................. 77
LIST ...................................................................................................................................................... 83
Member Functions of List ................................................................................................................... 84
MAPS ................................................................................................................................................... 92
Member Functions of Map ................................................................................................................. 93
STACK .................................................................................................................................................. 97
Member Functions of Stacks............................................................................................................... 97
QUEUE ............................................................................................................................................... 100
Member Functions of Queue ............................................................................................................ 100
PRIORITY QUEUE ............................................................................................................................... 102
Member Function of Priority Queue ................................................................................................. 103
DEQUE ............................................................................................................................................... 104
Member Functions of Deque ............................................................................................................ 105
Overview of Iterators in STL .............................................................................................................. 107
Operations on Iterators in STL .......................................................................................................... 109
Overview of algorithms in STL .......................................................................................................... 112
Sorting Algorithms in STL .................................................................................................................. 113
sort .................................................................................................................................................... 113
partial_sort........................................................................................................................................ 115
is_sorted............................................................................................................................................ 116
binary_search.................................................................................................................................... 117
equal_range ...................................................................................................................................... 119
upper_bound .................................................................................................................................... 120
lower_bound ..................................................................................................................................... 121
Non Modifying Algorithms in STL...................................................................................................... 121
count ................................................................................................................................................. 122
equal ................................................................................................................................................. 122
mismatch........................................................................................................................................... 124
search ................................................................................................................................................ 125
search_n ............................................................................................................................................ 126
Non Modifying Algorithms in STL...................................................................................................... 127
copy and copy_n ............................................................................................................................... 128
fill and fill_n....................................................................................................................................... 129
move ................................................................................................................................................. 130
transform .......................................................................................................................................... 131
generate and generate_n ................................................................................................................. 133
swap Method .................................................................................................................................... 134
swap_ranges ..................................................................................................................................... 135
reverse .............................................................................................................................................. 136
reverse_copy ..................................................................................................................................... 137
rotate ................................................................................................................................................ 138
unique ............................................................................................................................................... 139
unique_copy...................................................................................................................................... 141
Numeric Algorithms in STL ................................................................................................................ 143
iota Method ...................................................................................................................................... 143
accumulate Method .......................................................................................................................... 143
partial_sum Method ......................................................................................................................... 145
Minimum and Maximum operations in STL ...................................................................................... 146
max and min Method........................................................................................................................ 146
max_element and min_element Method ......................................................................................... 148
lexicographical_compare Method .................................................................................................... 150
MinMax and Permutation operations in STL .................................................................................... 150
minmax and minmax_element Method ........................................................................................... 151
next_permutation and prev_permutation Method ......................................................................... 153
Notes ................................................................................................................................................. 175
Difference between "C structure" and "C++ structure"

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.

What is difference between C and C++


[This is a usual C or C++ interview question, mostly the first one you will face if you are fresher or
appearing for campus interview. When answering this question please make sure you don't give the
text book type explanations, instead give examples from real software scenario. Answer for this
interview question can include below points, though its not complete list. This question itself can be a
1day interview !!!]

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.

4. What do you mean by C++ access specifiers?


[Questions regarding access specifiers are common not just in c++ interview but for other object oriented
language interviews as well.]
Access specifiers are used to define how the members (functions and variables) can be accessed outside the
class. There are three access specifiers defined which are public, private, and protected

 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.

5. What are the basics concepts of OOP?


[ A must OOP / c++ interview question for freshers (some times asked in interviews for 1-2 years experienced
also), which everybody answers as well. But the point is, it's not about the answer, but how you apply these
OOPs concepts in real life. You should be able to give real life examples for each of these concepts, so prepare
yourself with few examples before appearing for the interview. It has seen that even the experienced people get
confused when it comes to the difference between basic OOP concepts, especially abstraction and
encapsulation.]

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;
};

class MyStack : public Stack


{
private:
int arrayToHoldData[]; //Holds the data from stack

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.

6. What is the use of volatile keyword in c++? Give an example.


Most of the times compilers will do optimization to the code to speed up the program. For example in the below
code,
int a = 10;
while( a == 10){
// Do something
}
compiler may think that value of 'a' is not getting changed from the program and replace it with 'while(true)',
which will result in an infinite loop. In actual scenario the value of 'a' may be getting updated from outside of
the program.
Volatile keyword is used to tell compiler that the variable declared using volatile may be used from outside the
current scope so that compiler wont apply any optimization. This matters only in case of multi-threaded
applications.
In the above example if variable 'a' was declared using volatile, compiler will not optimize it. In shot, value of
the volatile variables will be read from the memory location directly.

7. In how many ways we can initialize an int variable in C++?


In c++, variables can be initialized in two ways, the traditional C++ initialization using "=" operator and second
using the constructor notation.

 Traditional C++ initilization

int i = 10;
variable i will get initialized to 10.

 Using C++ constructor notation

int i(10);

8. What is implicit conversion/coercion in c++?


Implicit conversions are performed when a type (say T) is used in a context where a compatible type (Say F) is
expected so that the type T will be promoted to type F.

short a = 2000 + 20;

In the above example, variable a will get automatically promoted from short to int. This is called implicit
conversion/coercion in c++.

9. What are C++ inline functions?


C++ inline functions are special functions, for which the compiler replaces the function call with body/definition
of function. Inline functions make the program execute faster than the normal functions, since the overhead
involved in saving current state to stack on the function call is avoided. By giving developer the control of
making a function as inline, he can further optimize the code based on application logic. But actually, it's the
compiler that decides whether to make a function inline or not regardless of it's declaration. Compiler may choose
to make a non-inline function inline and vice versa. Declaring a function as inline is in effect a request to the
compiler to make it inline, which compiler may ignore. So, please note this point for the interview that, it is upto
the compiler to make a function inline or not.

inline int min(int a, int b)


{
return (a < b)? a : b;
}

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

 Contents of source file


 Plus contents of files included directly or indirectly
 Minus source code lines ignored by any conditional pre processing directives ( the lines ignored by
#ifdef,#ifndef etc)

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.

12. What do you mean by storage classes?


Storage class are used to specify the visibility/scope and life time of symbols(functions and variables). That
means, storage classes specify where all a variable or function can be accessed and till what time those variables
will be available during the execution of program.

13. How many storage classes are available in C++?


Storage class are used to specify the visibility/scope and life time of symbols(functions and variables). That
means, storage classes specify where all a variable or function can be accessed and till what time those variables
will be available during the execution of program.
Following storage classes are available in C++

 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

C++ Storage Storage Scope Of


Life Time
Specifier Location Variable

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)

14. What is 'Copy Constructor' and when it is called?


This is a frequent c++ interview question. Copy constructor is a special constructor of a class which is used to
create copy of an object. Compiler will give a default copy constructor if you don't define one. This implicit
constructor will copy all the members of source object to target object.
Implicit copy constructors are not recommended, because if the source object contains pointers they will be
copied to target object, and it may cause heap corruption when both the objects with pointers referring to the
same location does an update to the memory location. In this case its better to define a custom copy constructor
and do a deep copy of the object.

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. }

15. What is realloc() and free()? What is difference between them?

 void* realloc (void* ptr, size_t size)

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().

 void free (void* ptr)

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.

17. What do you mean by persistent and non persistent objects?


[This question may be asked in many ways during c++ interviews, like how to send an object to a remote
computer or how to save the your program state across application restarts. All these are related to
serialization.]
Persistent objects are the ones which we can be serialized and written to disk, or any other stream. So before
stopping your application, you can serialize the object and on restart you can deserialize it. [ Drawing
applications usually use serializations.]
Objects that can not be serialized are called non persistent objects. [ Usually database objects are not serialized
because connection and session will not be existing when you restart the application. ]

Is it possible to get the source code back from binary file

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.

What are virtual functions and what is its use


[This is a sure question in not just C++ interviews, but any other OOP language interviews. Virtual functions are the
important concepts in any object oriented language, not just from interview perspective. Virtual functions are
used to implement run time polymorphism in c++.]
Virtual functions are member functions of class which is declared using keyword 'virtual'. When a base class
type reference is initialized using object of sub class type and an overridden method which is declared as virtual
is invoked using the base reference, the method in child class object will get invoked.

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++).

How to create a pure virtual function?


A function is made as pure virtual function by the using a specific signature, " = 0" appended to the
function declaration as given below,

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.

22. What is virtual destructors? Why they are used?


[This c++ interview question is in a way related to polymorphism.]
Virtual destructors are used for the same purpose as virtual functions. When you remove an object of subclass, which is
referenced by a parent class pointer, only destructor of base class will get executed. But if the destructor is defined using
virtual keyword, both the destructors [of parent and sub class] will get invoked.

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.

 During compilation : This is called early binding

For all the direct function references compiler will replace the reference with actual address of the method.

 At runtime: This is called late binding.

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.

Dynamic binding is another name for late binding.

24. What is meant by reference variable in C++?

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).

How to create a reference variable in C++ :


Appending an ampersand (&) to the end of datatype makes a variable eligible to use as reference variable.

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. }

Above code creates following output:


Value of a : 10
Value of a reference (b) : 10
Value of a : 20
Value of a reference (b) : 20

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 Reference Variables

References cannot be assigned NULL. It should always


Pointers can be assigned to NULL
be associated with actual memory, not NULL.

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
};

class Employee:public Person


{
public:
Employee(string fName, string lName, double sal)
{
FirstName = fName;
LastName = lName;
salary = sal;
}
string FirstName;
string LastName;
double salary;
void show()
{
cout << "First Name: " << FirstName << " Last Name: " << LastName << " Salary: " << salary<< endl;
}
void addBonus(double bonus)
{
salary += bonus;
}
};

class Manager :public Employee


{
public:
Manager(string fName, string lName, double sal, double comm) :Employee(fName, lName, sal)
{
Commision = comm;
}
double Commision;
double getComm()
{
return Commision;
}
};

class Clerk :public Employee


{
public:
Clerk(string fName, string lName, double sal, Manager* man) :Employee(fName, lName, sal)
{
manager = man;
}
Manager* manager;
Manager* getManager()
{
return manager;
}
};

void congratulate(Employee* emp)


{
cout << "Happy Birthday!!!" << endl;
emp->addBonus(200);
emp->show();
};

int main()
{
//pointer to base class object
Employee* emp;

//object of derived class


Manager m1("Steve", "Kent", 3000, 0.2);
Clerk c1("Kevin","Jones", 1000, &m1);

//implicit upcasting
emp = &m1;

//It's ok
cout<<emp->FirstName<<endl;
cout<<emp->salary<<endl;

//Fails because upcasting is used


//cout<<emp->getComm();

congratulate(&c1);
congratulate(&m1);

cout<<"Manager of "<<c1.FirstName<<" is "<<c1.getManager()->FirstName;


}

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:

//pointer to base class object


Employee* emp;
//object of derived class
Manager m1("Steve", "Kent", 3000, 0.2);
//implicit upcasting
emp = &m1;

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();

Example of upcasting usage


One of the biggest advantage of upcasting is the capability of writing generic functions for all the
classes that are derived from the same base class. Look on example:

void congratulate(Employee* emp)


{
cout << "Happy Birthday!!!" << endl;
emp->show();
emp->addBonus(200);
};

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);

Try to run this program:


Happy Birthday!!!
First Name: Kevin Last Name: Jones
Happy Birthday!!!
First Name: Steve Last: Name Kent
An example about how to use upcasting with virtual functions is described in "C++ Polymorphism"
topic.
Memory layout
As you know, derived class extends properties of the base class. It means that derived class has
properties (data members and member functions) of the base class and defines new data members
and member functions.
Look on the memory layout of the Employee and Manager classes:

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:

//pointer to base class object


Employee* emp;
//object of derived class
Manager m1("Steve", "Kent", 3000, 0.2);
//implicit upcasting
emp = &m1;
//explicit downcasting from Employee to Manager
Manager* m2 = (Manager*)(emp);
This code compiles and runs without any problem, because emp points to an object of Manager
class.
What will happen, if we try to downcast a base class pointer that is pointing to an object of base
class and not to an object of derived class? Try to compile and run this code:

Employee e1("Peter", "Green", 1400);


//try to cast an employee to Manager
Manager* m3 = (Manager*)(&e1);
cout << m3->getComm() << endl;

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:

virtual void foo() {}

Now you can use downcasting for converting Employee class pointers to derived classes pointers.

Employee e1("Peter", "Green", 1400);


Manager* m3 = dynamic_cast<Manager*>(&e1);
if (m3)
cout << m3->getComm() << endl;
else
cout << "Can't cast from Employee to Manager" << endl;

In this case, dynamic cast returns nullptr. Therefore, you will see a warning message.

Introduction to Classes and Objects


The classes are the most important feature of C++ that leads to Object Oriented programming. Class
is a user defined data type, which holds its own data members and member functions, which can be
accessed and used by creating instance of that class
More about Classes

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,

class Study, class StudyTonight etc

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,

Types of Member Functions


We already know what member functions are and what they do. Now lets study some special
member functins present in the class. Following are different types of Member functions,

1. Simple functions
2. Static functions
3. Const functions
4. Inline functions
5. Friend functions

Simple Member functions


These are the basic member function, which dont have any special keyword like static etc as prefix.
All the general member functions, which are of below given form, are termed as simple and basic
member functions.
return_type functionName(parameter_list)
{
function body;
}

Static Member functions


Static is something that holds its position. Static is a keyword which can be used with data members
as well as the member functions. We will discuss this in details later. As of now we will discuss its
usage with member functions only.
A function is made static by using static keyword with function name. These functions work for the
class as whole rather than for a particular object of a class.
It can be called using the object and the direct member access . operator. But, its more typical to
call a static member function by itself, using class name and scope resolution :: operator.
Example :
class X
{
public:
static void f(){};
};

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.

Const Member functions


We will study Const keyword in detail later, but as an introduction, Const keyword makes variables
constant, that means once defined, there values can't be changed.
When used with member function, such member functions can never modify the object or its related
data members.
//Basic Syntax of const Member Function

void fun() const {}

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

Help other team members for any technical related issues.


Enhance my skills with the help of other team members during knowledge sharing sessions.

What are you most proud of?

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.

What will you take away from this experience?

As I got opportunity to guide my teammates, I am getting experience related to next level of activities.

What actions will you take to improve or grow further?

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.

Enhance my skill set to meet client expectations

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.

What are you most proud of?

I have got knowledge on LATIS a Telecom building application. I have got understanding on various
modules of building application

Cycle Processing, Pricing, Taxing, Invoicing.

What will you take away from this experience?

Prior to this project I have got experience on SMSE applications related to Telecom. Now I have got
understanding about Telecom Billing application also.

What actions will you take to improve or grow further?

I would reach next level of proficiency in my skill set by attending online and classroom trainings.
WORK ON THE ASSIGNED DELEVIRABLES

DESCRIPTION

Attending daily standup calls and sprint meetings.


I would work on the assigned user stories and implement the code as per the requirements and
test the results.
I would make sure that my tasks in the user stories are completed within the sprint target
dates.

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.

What will you take away from this experience?

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 have enhanced my skillset in Python, C++ and PL/SQL.

What actions will you take to improve or grow further?

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"; }
};

class Sub : public Super


{ int y;
};

int main()
{
Super* ptr; // Super class pointer
Sub obj;
ptr = &obj;

Super &ref; // Super class's reference


ref=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

Functions that are never Inherited

 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.

Inheritance and Static Functions

1. They are inherited into the derived class.


2. If you redefine a static member function in derived class, all the other overloaded functions in
base class are hidden.
3. Static Member functions can never be virtual. We will study about Virtual in coming topics.

Hybrid Inheritance and Virtual Class


In Multiple Inheritance, the derived class inherits from more than one base class. Hence, in Multiple
Inheritance there are a lot chances of ambiguity.
class A
{ void show(); };

class B:public A {};

class C:public A {};

class D:public B, public C {};


int main()
{
D obj;
obj.show();
}

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 {};

class C : virtual public A {};

class D : public B, public C {};

Now by adding virtual keyword, we tell compiler to call any one out of the two show() funtions.

Hybrid Inheritance and Constructor call


As we all know that whenever a derived class object is instantiated, the base class constructor is
always called. But in case of Hybrid Inheritance, as discussed in above example, if we create an
instance of class D, then following constructors will be called :

 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

Requirements for 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.

Example of Function Overriding

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.

Function Call Binding with class Objects


Connecting the function call to the function body is called Binding. When it is done before the
program is run, its called Early Binding or Static Binding or Compile-time Binding.
class Base
{
public:
void shaow()
{
cout << "Base class\t";
}
};
class Derived:public Base
{
public:
void show()
{
cout << "Derived Class";
}
}

int main()
{
Base b; //Base class object
Derived d; //Derived class object
b.show(); //Early Binding Ocuurs
d.show();
}

Output : Base class Derived class


In the above example, we are calling the overrided function using Base class and Derived class
object. Base class object will call base version of the function and derived class's object will call the
derived version of the function.

Function Call Binding using Base class Pointer


But when we use a Base class's pointer or reference to hold Derived class's object, then Function
call Binding gives some unexpected results.
class Base
{
public:
void show()
{
cout << "Base class";
}
};
class Derived:public Base
{
public:
void show()
{
cout << "Derived Class";
}
}

int main()
{
Base* b; //Base class pointer
Derived d; //Derived class object
b = &d;
b->show(); //Early Binding Occurs
}

Output : Base class


In the above example, although, the object is of Derived class, still Base class's method is called.
This happens due to Early Binding.
Compiler on seeing Base class's pointer, set call to Base class's show() function, without knowing
the actual object type.
Virtual Functions
Virtual Function is a function in base class, which is overrided in the derived class, and which tells
the compiler to perform Late Binding on this function.
Virtual Keyword is used to make a member function of the base class Virtual.

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.

Problem without Virtual Keyword


class Base
{
public:
void show()
{
cout << "Base class";
}
};
class Derived:public Base
{
public:
void show()
{
cout << "Derived Class";
}
}

int main()
{
Base* b; //Base class pointer
Derived d; //Derived class object
b = &d;
b->show(); //Early Binding Ocuurs
}

Output : Base class


When we use Base class's pointer to hold Derived class's object, base class pointer or reference will
always call the base version of the function

Using Virtual Keyword


We can make base class's methods virtual by using virtual keyword while declaring them. Virtual
keyword will lead to Late Binding of that method.
class Base
{
public:
virtual void show()
{
cout << "Base class";
}
};
class Derived:public Base
{
public:
void show()
{
cout << "Derived Class";
}
}

int main()
{
Base* b; //Base class pointer
Derived d; //Derived class object
b = &d;
b->show(); //Late Binding Ocuurs
}

Output : Derived class


On using Virtual keyword with Base class's function, Late Binding takes place and the derived
version of function will be called, because base class pointer pointes to Derived class object.

Using Virtual Keyword and Accessing Private Method of Derived class


We can call private function of derived class from the base class pointer with the help of virtual
keyword. Compiler checks for access specifier only at compile time. So at run time when late binding
occurs it does not check whether we are calling the private function or public function.
#include
using namespace std;

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();
}

Output : Derived class


Mechanism of Late Binding

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.

Important Points to Remember

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.

Characteristics of 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.

Pure Virtual Functions


Pure virtual Functions are virtual functions with no definition. They start with virtual keyword and
ends with = 0. Here is the syntax for a pure virtual function,
virtual void f() = 0;

Example of Abstract Class

class Base //Abstract base class


{
public:
virtual void show() = 0; //Pure Virtual Function
};

class Derived:public Base


{
public:
void show()
{ cout << "Implementation of Virtual Function in Derived class"; }
};

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.

Why can't we create Object of Abstract Class ?


When we create a pure virtual function in Abstract class, we reserve a slot for a function in the
VTABLE(studied in last topic), but doesn't put any address in that slot. Hence the VTABLE will be
incomplete.
As the VTABLE for Abstract class is incomplete, hence the compiler will not let the creation of object
for such class and will display an errror message whenever you try to do so.

Pure Virtual definitions

 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.

class Base //Abstract base class


{
public:
virtual void show() = 0; //Pure Virtual Function
};

void Base :: show() //Pure Virtual definition


{
cout << "Pure Virtual definition\n";
}

class Derived:public Base


{
public:
void show()
{ cout << "Implementation of Virtual Function in Derived class"; }
};

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.

Upcasting without Virtual Destructor


Lets first see what happens when we do not have a virtual Base class destructor.
class Base
{
public:
~Base() {cout << "Base Destructor\t"; }
};

class Derived:public Base


{
public:
~Derived() { cout<< "Derived Destructor"; }
};

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.

Upcasting with Virtual Destructor


Now lets see. what happens when we have Virtual destructor in the base class.
class Base
{
public:
virtual ~Base() {cout << "Base Destructor\t"; }
};

class Derived:public Base


{
public:
~Derived() { cout<< "Derived Destructor"; }
};

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

 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
};

Base::~Base() { cout << "Base Destructor"; } //Definition of Pure Virtual Destructor

class Derived:public Base


{
public:
~Derived() { cout<< "Derived Destructor"; }
};
Operator Overloading
Operator overloading is an important concept in C++. It is a type of polymorphism in which an
operator is overloaded to give user defined meaning to it. Overloaded operator is used to perform
operation on user-defined data type. For example '+' operator can be overloaded to perform addition
on various data types, like for Integer, String(concatenation) etc.

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

Implementing Operator Overloading


Operator overloading can be done by implementing a function which can be :

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.

Restrictions on Operator Overloading


Following are some restrictions to be kept in mind while implementing operator overloading.

1. Precedence and Associativity of an operator cannot be changed.


2. Arity (numbers of Operands) cannot be changed. Unary operator remains unary, binary remains
binary etc.
3. No new operators can be created, only existing operators can be overloaded.
4. Cannot redefine the meaning of a procedure. You cannot change how integers are added.

Operator Overloading Examples


Almost all the operators can be overloaded in infinite different ways. Following are some examples
to learn more about operator overloading. All the examples are closely connected.
Overloading Arithmetic Operator
Arithmetic operator are most commonly used operator in C++. Almost all arithmetic operator can be
overloaded to perform arithmetic operation on user-defined data type. In the below example we have
overridden the + operator, to add to Time(hh:mm:ss) objects.

Example: overloading '+' Operator to add two time object

#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();
}

Overloading I/O operator

 Overloaded to perform input/output for user defined datatypes.


 Left Operand will be of types ostream& and istream&
 Function overloading this operator must be a Non-Member function because left operand is not
an Object of the class.
 It must be a friend function to access private data members.

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.

Example: overloading '<<' Operator to print time object


#include< iostream.h>
#include< conio.h>
class time
{
int hr,min,sec;
public:
time()
{
hr=0, min=0; sec=0;
}

time(int h,int m, int s)


{
hr=h, min=m; sec=s;
}
friend ostream& operator << (ostream &out, time &tm); //overloading '<<' operator
};

ostream& operator<< (ostream &out, time &tm) //operator function


{
out << "Time is " << tm.hr << "hour : " << tm.min << "min : " << tm.sec << "sec";
return out;
}

void main()
{
time tm(3,15,45);
cout << tm;
}

Output
Time is 3 hour : 15 min : 45 sec

Overloading Relational operator


You can also overload Relational operator like == , != , >= , <= etc. to compare two user-defined
object.

Example

class time
{
int hr,min,sec;
public:
time()
{
hr=0, min=0; sec=0;
}

time(int h,int m, int s)


{
hr=h, min=m; sec=s;
}
friend bool operator==(time &t1, time &t2); //overloading '==' operator
};
bool operator== (time &t1, time &t2) //operator function
{
return ( t1.hr == t2.hr &&
t1.min == t2.min &&
t1.sec == t2.sec );
}

Copy constructor Vs. Assignment operator


Assignment operator is used to copy the values from one object to another already existing
object. For example
time tm(3,15,45); //tm object created and initialized
time t1; //t1 object created
t1 = tm; //initializing t1 using tm

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.

Use and Application of STL


STL being generic library provide containers and algorithms which can be used to store and
manipulate different types of data thus it saves us from defining these data structures and algorithms
from the scratch. Because of STL, now we do not have to define our sort function every time we
make a new program or define same function twice for the different data types, instead we can just
use the generic container and algorithms in STL.
This saves a lot of time, code and effort during programming, thus STL is heavily used in the
competitive programming, plus it is reliable and fast.

What are Containers?


Containers Library in STL gives us the Containers, which in simplest words, can be described as the
objects used to contain data or rather collection of object. Containers help us to implement and
replicate simple and complex data structures very easily like arrays, list, trees, associative arrays
and many more.
The containers are implemented as generic class templates, means that a container can be used to
hold different kind of objects and they are dynamic in nature!
Following are some common containers :

 vector : replicates arrays


 queue : replicates queues
 stack : replicates stack
 priority_queue : replicates heaps
 list : replicates linked list
 set : replicates trees
 map : associative arrays

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.

Using Container Library


Below is an example of implementing linked list, first by using structures and then by list containers.
#include <iostream>
struct node
{
int data;
struct node * next;
}

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.

Some Commonly used Functions


Here are some function for pair template :

 Operator = : assign values to a pair.


 swap : swaps the contents of the pair.
 make_pair() : create and returns a pair having objects defined by parameter list.
 Operators( == , != , > , < , <= , >= ) : lexicographically compares two pairs.

Program demonstrating PAIR Template


#include <iostream>

using namespace std;

int main ()
{
pair<int,int> pair1, pair3; //creats pair of integers
pair<int,string> pair2; // creates pair of an integer an a string

pair1 = make_pair(1, 2); // insert 1 and 2 to the pair1


pair2 = make_pair(1, "Studytonight") // insert 1 and “Nikhilesh” in pair2
pair3 = make_pair(2, 4)
cout<< pair1.first << endl; // prints 1, 1 being 1st element of pair1
cout<< pair2.second << endl; // prints Studytonight

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 :

 A Constructor to construct a new tuple


 Operator = : to assign value to a tuple
 swap : to swap value of two tuples
 make_tuple() : creates and return a tuple having elements described by the parameter list.
 Operators( == , != , > , < , <= , >= ) : lexicographically compares two pairs.
 Tuple_element : returns the type of tuple element
 Tie : Tie values of a tuple to its refrences.

Program demonstrating Tuple template


#include <iostream>

int main ()
{
tuple<int, int, int> tuple1; //creates tuple of integers
tuple<int, string, string> tuple2; // creates pair of an integer an 2 string

tuple1 = make_tuple(1,2,3); // insert 1, 2 and 3 to the tuple1


tuple2 = make_pair(1,"Studytonight","Loves You");
/* insert 1, "Studytonight" and "Loves You" in tuple2 */

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 */

cout << id <<" "<< first_name <<" "<< last_name;


/* prints 1 Studytonight Loves You */

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.

Member Functions of array template


Following are the important and most used member functions of array template.

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>

using namespace std;

int main ()
{
array<int,10> array1 = {1,2,3,4,5,6,7,8,9};

cout << array1.at(2) // prints 3


cout << array1.at(4) // prints 5

[ ] 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};

a.swap(b) // swaps array a and b

cout << "a is : ";


for(int i=0; i < 8; i++) {
cout << a[i] <<" ";
}
cout << endl;
cout << "b is : ";
for(int i=0; i < 8; i++) {
cout << a[i] <<" ";
}
/* ouput will be
a is : 8 7 6 5 4 3 2 1
b is : 1 2 3 4 5 6 7 8 */
}

operators ( == , != , > , < , >= , <= )


All these operators can be used to lexicographically compare values of two arrays.

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.

Member Functions of Vector


push_back
push_back() is used for inserting an element at the end of the vector. If the type of object passed as
parameter in the push_back() is not same as that of the vector or is not interconvertible an exception
is thrown.
The following illustration will show how push_back() works :
#include <iostream>
#include <vector>

using namespace std;

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

for(vector<int>::iterator i = v.begin(); i != v.end(); i++) {


cout << *i <<" "; // for printing the vector
}
}
/* Output : 1 2 4 */

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>

using namespace std;

int main()
{
vector<int> v1 {10,20,30,40};

v1.pop_back();

vector<int>::iterator it;

for(it = v.begin(); it != v.end(); it++) {


cout << *it <<" "; // for printing the vector
}
}
/* Output : 10 20 30 */

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>

using namespace std;

int main()
{
vecto<int>v1 {10,20,30,40};
vector<int>iterator:: it = v.begin();

v.erase(it); //removes first element from the vector

v.erase(v1.begin(), v1.end() - 2 )
/*removes all the elements except last two */

for(it = v.begin(); it != v.end(); it++) {


cout << *it <<" "; // for printing the vector
}
}

/* 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>

using namespace std;

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*/
}

Member Functions of List


insert
This method, as the name suggests, inserts an element at specific position, in a list. There are 3
variations of insert(), they are as follows :

 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>

using namespace std;

int main()
{
list<int> l = {1,2,3,4,5};
list<int>::iterator it = l.begin();

l.insert (it+1, 100); // insert 100 before 2 position


/* now the list is 1 100 2 3 4 5 */

list<int> new_l = {10,20,30,40}; // new list

new_l.insert (new_l.begin() , l.begin(), l.end());


/* insert elements from beginning of list l to end of list l
before 1 position in list new_l */

/* now the list new_l is 1 100 2 3 4 5 10 20 30 40 */

l.insert(l.begin() , 5 , 10); // insert 10 before beginning 5 times


/* now l is 10 10 10 10 10 1 100 2 3 4 5 */

return 0;
}

push_back and push_front


push_back(element) method is used to push elements into a list from the back.
push_front(element) method is used to push elements into a list from the front.

#include <iostream>
#include <list>

using namespace std;

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 */

pop_back and pop_front


pop_front() removes first element from the start of the list. While pop_back() removes first element
from the end of the list.
#include <iostream>
#include <list>

using namespace std;

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>

using namespace std;

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>

using namespace std;

bool compare_function( string& s1 , string& s2 )


{
return ( s1.length() > s2.length() );
}

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 :

 splice(iterator, list_name) : Transfers complete list list_name at position pointed by the


iterator.
 splice(iterator, list_name, iterator_pos) : Transfer elements pointed by iterator_pos from
list_name at position pointed by iterator.
 splice(iterator, list_name, itr_start, itr_end) : Transfer range specified by itr_start and
itr_end from list_name at position pointed by iterator.
#include <iostream>
#include <list>

using namespace std;

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 */

list2.splice(list2.begin(), list1, it);


/* transfer element pointed by it in list1 to the beginning of list2 */
/* list2 is now 5 and list1 is 1 6 7 8 2 3 4*/

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>

using namespace std;

int main ()
{
list<int> list1 = {1,3,5,7,9};
list<int> list2 = {2,4,6,8,10};

/* both the lists are sorted. In case they are not ,


first they should be sorted by sort function() */

list1.merge(list2);

/* list list1 is now 1,2,3,4,5,6,7,8,9,10 */

cout << list1.size() << endl; // prints 10


}

Lexicographically comparing Lists


Since lists are collection of elements, thus they do not have a standard value of their own. Thus in
order to compare list or vectors we compare their elements in their lexicographical order.
For example, let list1 = { 1 , 2 , 3} and list2 = { 1 , 3 , 2 }, now if we want to check if the list1 is greater
than list2 or not, we just check the element of each list in the order they appear in the lists. Since 1 in
list1 is equal to 1 in list2, we proceed further, now 2 in list1 is smaller then 3 in list2, thus list2 is
lexicographically greater than list1.
Operators == , > , < , <= , >= can be used to compare lists lexicographically.
MAPS
Maps are used to replicate associative arrays. Maps contain sorted key-value pair, in which each
key is unique and cannot be changed, and it can be inserted or deleted but cannot be altered. Value
associated with keys can be altered. We can search, remove and insert in a map within O(n) time
complexity.
For example : A map of students where roll number is the key and name is the value can be
represented graphically as :

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>

using namespace std;


int main ()
{
map<int,int> m{ {1,2} , {2,3} , {3,4} };
/* creates a map m with keys 1,2,3 and
their corresponding values 2,3,4 */

map<string,int> map1;
/* creates a map with keys of type character and
values of type integer */

map1["abc"]=100; // inserts key = "abc" with value = 100


map1["b"]=200; // inserts key = "b" with value = 200
map1["c"]=300; // inserts key = "c" with value = 300
map1["def"]=400; // inserts key = "def" with value = 400

map<char,int> map2 (map1.begin(), map1.end());


/* creates a map map2 which have entries copied
from map1.begin() to map1.end() */

map<char,int> map3 (m);


/* creates map map3 which is a copy of map m */
}

Member Functions of Map


at and [ ]
Both at and [ ] are used for accessing the elements in the map. The only difference between them
is that at throws an exception if the accessed key is not present in the map, on the other hand
operator [ ] inserts the key in the map if the key is not present already in the map.
#include <iostream>
#include <map>
using namespace std;

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.at(1) = "vikas"; // changes the value associated with key 1 to “vikas”


m[2] = "navneet"; // changes the value associated with key 2 to “navneet”

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 and insert_or_assign


insert() is used to insert entries in the map. Since keys are unique in a map, it first checks that
whether the given key is already present in the map or not, if it is present the entry is not inserted in
the map and the iterator to the existing key is returned otherwise new entry is inserted in the map.
There are two variations of insert() :

 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>

using namespace std;

int main ()
{
map<int,int> m{{1,2} , {2,3} , {3,4} };

m.insert( pair<int,int> (4,5));


/* inserts a new entry of key = 4 and value = 5 in map m */

/* make_pair() can also be used for creating a pair */


m.insert( make_pair(5, 6));
/* inserts a new entry of key = 5 and value = 6 */
map::iterator i , j;
i = m.find(2); // points to entry having key =2
j = m.find(5); // points to entry having key =5

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 */

m.insert_or_assign( make_pair(3,6)); // assign value = 6 to key =3


}

erase and clear


erase() removes the entry from the map pointed by the iterator (which is passed as parameter),
however if we want to remove all the elements from the map, we can use clear(), it clears the map
and sets its size to 0.
There are two variations of erase :

 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.

begin, end and find


begin, end and find returns an iterator. begin() returns the iterator to the starting entry of the map,
end() returns the iterator next to the last entry in the map and find() returns the iterator to the entry
having key equal to given key (passed as parameter).
STACK
The stack container is used to replicate stacks in c++, insertion and deletion is always performed at
the top of the stack.
To know more about the Stack data Structure, visit : STACK Data Structure
Here is the syntax of defining a stack in stl :
stack<object_type> stack_name;

The above statement will create a stack named stack_name of type object_type.

Member Functions of Stacks


push
push() is used to insert the element in the stack, the elements are inserted at the top of the stack.
#include <iostream>
#include <stack>

using namespace std;

int main ()
{
stack<int> s; // creates an empty stack of integer s

s.push(2); // pushes 2 in the stack , now top =2


s.push(3); // pushes 3 in the stack , now top =3

}
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()

size and empty


size() returns the number of elements present in the stack, whereas empty() checks if the stack is
empty or not. empty returns true if the stack is empty else false is returned.

swap
This method swaps the elements of the two stacks.
#include <iostream>
#include <stack>
using namespace std;

int main ()
{
stack<int> s;

// pushing elements into stack


s.push(2);
s.push(3);
s.push(4);

cout << s.top(); // prints 4, as 4 is the topmost element

cout << s.size(); // prints 3, as there are 3 elements in


}

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.

Member Functions of Queue


push
push() is used to insert the element in the queue. The element is inserted at the back or rear of the
queue.
#include <iostream>
#include <queue>

using namespace std;

int main ()
{
queue <int> q; // creates an empty queue of integer q

q.push>(2); // pushes 2 in the queue , now front = back = 2


q.push(3); // pushes 3 in the queue , now front = 2 , and back = 3
}

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>

using namespace std;

int main ()
{
queue <int> q; // creates an empty queue of integer q

q.push>(2); // pushes 2 in the queue , now front = back = 2


q.push(3); // pushes 3 in the queue , now front = 2 , and back = 3

q.pop() ; // removes 2 from the stack , front = 3


}

front and back


front() returns the front element of the queue whereas back() returns the element at the back of
the queue. Note that both returns the element, not removes it, unlike pop().

size and empty


size() returns the number of elements present in the queue, whereas empty() checks if the queue is
empty or not. empty returns true if the queue is empty else false is returned.

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;

Member Function of Priority Queue


push
This method inserts an element in the priority_queue. The insertion of the elements have time
complexity of logarithmic time.
#include <iostream>>
#include <queue>

using namespace std;

int main ()
{
priority_queue<int> pq1;

pq1.push(30); // inserts 30 to pq1 , now top = 30


pq1.push(40); // inserts 40 to pq1 , now top = 40 ( maxinmum element)
pq1.push(90); // inserts 90 to pq1 , now top = 90
pq1.push(60); // inserts 60 to pq1 , top still is 90

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;

pq1.push(30); // inserts 30 to pq1 , now top = 30


pq1.push(40); // inserts 40 to pq1 , now top = 40 ( maxinmum element)
pq1.push(90); // inserts 90 to pq1 , now top = 90
pq1.push(60); // inserts 60 to pq1 , top still is 90

pq1.pop(); // removes 90 ( greatest element in the queue

return 0;
}

top
This method returns the element at the top of the priority_queue which is the greatest element
present in the queue.

empty and size


size() returns the number of element present in the priority _queue, whereas empty() returns
Boolean true if the priority_queue is empty else Boolean false is returned.

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;

Member Functions of Deque


push_back, push_front and insert
push_back(element e) inserts an element e at the back of the deque, push_front(element e) inserts
the element e at the front of the deque.
insert() method has three variations :

 insert(iterator i, element e) : Inserts element e at the position pointed by iterator i in the


deque.
 insert(iterator i, int count, element e) : Inserts element e, count number of times from
the position pointed by iterator i.
 insert(iterator i, iterator first, iterator last) : Inserts the element in the range
[first,last] at the position pointed by iterator i in deque.

#include <iostream>
#include <deque>
#include <vector>

using namespace std;

int main ()
{

int a[] = { 1,5,8,9,3 };


deque<int> dq(a, a+5);
/* creates s deque with elements 1,5,8,9,3 */

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 */
}

pop_back and pop_front


pop_back() removes an element from the back of the deque whereas pop_front removes an
element from the front of the deque, both decreasing the size of the deque by one.
#include <iostream>
#include <deque>
#include <vector>

using namespace std;

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 */
}

empty, size and max_size


empty() returns Boolean true if the deque is empty, else Boolean false is returned. size() returns
the number of elements present in the deque and max_size() returns the number of element the
given deque can hold.

Swap
This method can be used to swap elements of two deques.

Overview of Iterators in STL


As we have discussed earlier, Iterators are used to point to the containers in STL, because of
iterators it is possible for an algorithm to manipulate different types of data structures/Containers.
Algorithms in STL don’t work on containers, instead they work on iterators, they manipulate the data
pointed by the iterators. Thus it doesn’'t matter what is the type of the container and because of this
an algorithm will work for any type of element and we don't have to define same algorithm for
different types of containers.
The above diagram shows to iterators i and j, pointing to the beginning and the end of a vector.

Defining an iterator
Syntax for defining an iterator is :
container_type <parameter_list>::iterator iterator_name;

Let's see an example for understanding iterators in a better way :


#include<iostream>
#include<vector>

using namespace std;

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;

for(i = v.begin(); i! = v.end(); i++)


cout << *i <<" ";
/* in the above for loop iterator I iterates though the
vector v and *operator is used of printing the element
pointed by it. */

return 0;
}

Operations on Iterators in STL


Following are the operations that can be used with Iterators to perform various actions.

 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 */

cout << distance(i,j) << endl;


/* prints 10 , */

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()

Overview of algorithms in STL


STL provide different types of algorithms that can be implemented upon any of the container with the
help of iterators. Thus now we don’t have to define complex algorithm instead we just use the built in
functions provided by the algorithm library in STL.
As already discussed earlier, algorithm functions provided by algorithm library works on the iterators,
not on the containers. Thus one algorithm function can be used on any type of container.
Use of algorithms from STL saves time, effort, code and are very reliable.
For example, for implementing binary search in C++, we would have to write a function such as :
bool binary_search( int l , int r , int key ,int a[])
{
if(l > r)
return -1;
else
{
int mid=(l+r)/2;

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())

Plus the above function will work on any type of container.

Types of algorithms in algorithm library

1. Sorting Algorithms
2. Search algorithms
3. Non modifying algorithms
4. Modifying algorithms
5. Numeric algorithms
6. Minimum and Maximum operations.

Sorting Algorithms in STL


We will be studying about three methods under Sorting Algorithms, namely :

 sort
 is_sorted
 partial_sort

sort
This function of the STL, sorts the contents of the given range. There are two version of sort() :

1. sort(start_iterator, end_iterator ) : sorts the range defined by iterators start_iterator and


end_iterator in ascending order.
2. sort(start_iterator, end_iterator, compare_function) : this also sorts the given range but
you can define how the sorting should be done by compare_function.
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

bool compare_function(int i, int j)


{
return i > j; // return 1 if i>j else 0
}
bool compare_string(string i, string j)
{
return (i.size() < j.size());
}

int main()
{
int arr[5] = {1,5,8,4,2};

sort(arr , arr+5); // sorts arr[0] to arr[4] in ascending order


/* now the arr is 1,2,4,5,8 */

vector<int> v1;

v1.push_back(8);
v1.push_back(4);
v1.push_back(5);
v1.push_back(1);

/* now the vector v1 is 8,4,5,1 */


vector<int>::iterator i, j;
i = v1.begin(); // i now points to beginning of the vector v1
j = v1.end(); // j now points to end of the vector v1

sort(i,j); //sort(v1.begin() , v1.end() ) can also be used


/* now the vector v1 is 1,4,5,8 */

/* use of compare_function */
int a2[] = { 4,3,6,5,6,8,4,3,6 };

sort(a2,a2+9,compare_function); // sorts a2 in descending order


/* here we have used compare_function which uses operator(>),
that result into sorting in descending order */

/* compare_function is also used to sort non-numeric elements such as*/

string s[]={"a" , "abc", "ab" , "abcde"};

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};

partial_sort(a, a+4, a+9);


/* now a is 1,2,3,4,9,8,7,6,5 */

int b[] = {1,5,6,2,4,8,9,3,7};

/* sorts b such that first 4 elements are the greatest elements


in the array and are in descending order */
partial_sort(b, b+4, b+9);
/* now b is 9,8,7,6,1,2,4,3,5 */
}

is_sorted
This function of the STL, returns true if the given range is sorted. There are two version of
is_sorted() :

1. is_sorted(start_iterator, end_iterator) : Checks the range defined by iterators start_iterator


and end_iterator in ascending order.
2. is_sorted(start_iterator, end_iterator, compare_function) : It also checks the given range
but you can define how the sorting must be done.

#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);

/* now the vector v1 is 8,4,5,1 */


cout<<is_sorted(v1.begin() , v1.end() );
/* prints 0 */
sort(v1.begin() , v1.end() );
/* sorts the vector v1 */
cout<<is_sorted(v1.begin() , v1.end());
/* prints 1 , as vector v1 is sorted */
}
binary_search
This function returns Boolean true if the element is present in the given range, else Boolean false is
returned. There are two variations of binary_search():

 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;

bool compare_string_by_length (string i,string j)


{
return (i.size() == j.size());
}

int main ()
{
int inputs[] = {7,8,4,1,6,5,9,4};
vector v(inputs, inputs+8);

cout<<binary_search(v.begin() , v.end() , 7 ); //prints 1 , Boolean true

cout<<binary_search(v.begin() , v.end() , 217); //prints 0 , Boolean false

/* compare_function can be used to search


non numeric elements based on their properties */

string s[] = { "test" , "abcdf" , "efghijkl" , "pop" };

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;

bool compare_function (int i,int j) { return (i <= j); }

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);

pair< vector<int>::iterator, vector<int>::iterator > sub_range;


/* defining the pair of two iterators to an integer vector */

sub_range = equal_range (v.begin(), v.end(), 2);


/* now sub_range.first points to 4th element in the vector v and
sub_range.second points to 7th element ,
note that sub_range.secong points to the element
which is next to the element in the subrange */

sub_range = equal_range (v.begin(), v.end(), 20, compare_function);


/* sub_range.first points to first element in the vector v ,
as it satisfy the condition exerted by compare_function , <= ,
sub_range.second points to 7th element in the vector . */
}

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);

vector<int>::iterator it1 , it2;

it1 = upper_bound(v.begin(), v.end(), 6);


/* points to eight element in v */

it2 = upper_bound(v.begin(), v.end(), 4);


/* points to seventh element in v */
}
lower_bound
lower_bound() returns an iterator to the elements in the given range which does no compare less
than the given value. The range given should be already sorted for lower_bound() to work properly.
In other words it returns an iterator to the lower 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);

vector<int>::iterator it1 , it2;

it1 = lower_bound(v.begin(), v.end(), 4);


/* points to fifth element in v */

it2 = lower_bound (v.begin(), v.end(), 10);


/* points to second last element in v */
}
Non Modifying Algorithms in STL
Following are some non-modifying algorithms in Standard Template library that we will be covering :

 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};

int count_5 = count(values, values+15, 5);


/* now count_5 is equal to 4 */

vector<int> v(values, values+15);

int count_1 = count(v.begin(), v.end(), 1);


/* now count_1 is equal to */

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;

bool cmp_string(string i, string j)


{
return (i.size() == j.size());
}

int main()
{
int inputs1[] = { 1,2,3,4,5,6,7,8};
int inputs2[] = { -1,2,1,2,3,4,6,7,8,9};

vector<int> v1(inputs1 , inputs1+9 );


vector<int> v2(inputs2 , inputs2+10 );

cout<<equal(v1.begin(), v1.end(), v2.begin()+2 ) ; // prints 0 , boolean false

/* use of compare function */


string s1[] = { "abc" , "def" , "temp" , "testing" };
string s2[] = { "xyz" , "emp" , "resr" , "testing" };

cout<<equal( s1 , s1+4 , s2 , cmp_string); // prints 1


/* note that the stings in s1 and s2 are not actually
equal but still equal() returns 1 , beacause we are defining
equality of two string by their length in cmp_function */
}

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;

bool cmp_string(string i , string j)


{
return ( i.size() == j.size() );
}

int main()
{
int inputs1[] = {1,2,3,4,5,6,7,8};
int inputs1[] = {-1,2,1,2,3,4,6,7,8,9};

vector<int> v1(inputs1 ,inputs1+9);


vector<int> v2(inputs2 ,inputs2+9);
pair<vector<int<::iterartor, vector<int>::iterator> position;
/* defining a pair of iterator to the vector of integer */

position = mismatch(v1.begin(), v1.end(), v2.begin()+2) ;

/* now position.first is an iterator pointing


to the 5th element in the vector v1 and position.second
points to the 7th element in the vector v2 */

/* use of compare function */


string s1[] = {"abc", "def", "temp", "testing"};
string s2[] = {"xyz", "emp", "res", "testing"};

pair<string::iterator, string::iterator> position2;

position2 = mismatch( s1, s1+4, s2, cmp_string);


/* now position2.first is an iterator pointing
to the 3rd element in s1 and position2.second points
to the 3rd element in the s2 */
}

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> v1(inputs1, inputs1+9);


vector<int> v2(inputs2, inputs2+3);

vector<int>::iterator i ,j;

i = search(v1.begin(), v1.end(), v2.begin(), v2.end());

/* now i points to the second element in v1 */

j = search(v1.begin()+2, v1.end(), v2.begin(), v2.end());

/* j now points to the end of v1 as no sequence is equal to 2,3,4 in


[v1.begin()+2 ,v1.end()] */
}

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};

vector<int> v1(inputs1, inputs1+11);


vector<int>::iterator I;

i = search_n(v1.begin(), v1.end(), 3, 4);

/* now i points to the 4th element in v1 */

j = search(v1.begin()+2, v1.end(), 2, 5);

/* j now points to the end of v1 as no sequence is equal to 5,5 in


[v1.begin()+2 ,v1.end() ). */
}
Non Modifying Algorithms in STL
Following are some Modifying algorithms in Standard Template library that we will be covering :

 copy and copy_n


 fill and fill_n
 move
 transform
 generate
 swap
 swap_ranges
 reverse
 reverse_copy
 rotate
 unique
 unique_copy

copy and copy_n


copy method
This method copies the elements from the range defined by two iterators first and last into the
range starting by the iterator first2.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int main ()
{
vector<int> v1,v2;

v1.push(2);
v1.push(4);
v1.push(6);
v1.push(8);
v1.push(10);

copy(v1.begin(), v1.end(), v2.begin());

/* 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;

copy_n(v1.begin(), 5, v2.begin()); // copies first 5 elements from v1 to v2.


/* v2 is now 1,2,3,4,5 */
}

fill and fill_n


fill method
This method assigns the element a given value in the range defined by two iterators first and last.
Syntax for fill() is, fill(iterator first, iterator last, int value) .
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int main ()
{
vector<int> v1(10); // v1 is now 0,0,0,0,0,0,0,0,0,0

fill(v.begin(), v.end(), 5);


/* now v1 is 5,5,5,5,5,5,5,5,5,5 */

fill(v.begin(), v.end() - 5, 3);

/* now v11 is 3,3,3,3,3,5,5,5,5,5 */


}

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;

// inserts "nicky" in name , a is still = nicky


name.push_back(a);
// inserts "Vicky" in name , b is now NULL
name.push_back(move(b));
}

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.

 transform(iterator first1, iterator last1, iterator res, unaryoperation op) : This


method performs unary operation op on the elements in range [first1,last1] and stores the result
in range starting from res.
 transform(iterator first1, iterator last1, iterator first2, iterator res,
unaryoperation op) : This method performs binary operation op on the elements in range
[first1,last1] with the elements in the range starting with iterator first2 and stores the result in
range starting from res.

#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;

for(int i=0; i < 10; i++)


{
v2.push_back(i);
v1.push_back(i*10);
}

/* v2 : 1,2,3,4,5,6,7,8,9 */
/* v1 : 10,20,30,40,50,60,70,80,90 */

res2.resize(10);

transform(v2.begin(), v2.end(), res1.begin(), unaryoperation);


/* now res1 is : 2,4,6,8,10,12,14,16,18 */
}
generate and generate_n
generate method
This method assigns all the elements in the given range to the value returned by the successive call
to function generate_element. Syntax for generate is generate(iterator first, iterator last,
generator_function generate_element).

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>

using namespace std;

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) ;

/* this assign each element a random value generated


by the generate_random() */

generate_n(v2.begin(), 5, generate_random);

/* this assign first 5 elements a random value


and rest of the elements are un changed */
}

swap Method
This method swaps the elements of two container of same type.
#include <iostream>
#include <utility>
#include <vector>

using namespace std;

int main ()
{
int a = 6;
int b = 9;

swap(a,b);
/* a = 9 , b=6 */

/* you can also swap an entire container with swap */

vector<int> v, c;
for(int j=0; j < 10; j++)
{
v.push_back(j);
c.push_back(j+1);
}

swap(v,c);

for(vector>int>::iterator i = v.begin() ; i! = v.end() ; i++)


cout<<*i<<" ";

cout<<endl;

for(vector<int>::iterator k = c.begin() ; k! = c.end() ; k++)


cout<< *k <<" ";
}

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);
}

swap_ranges(v.begin(), v.begin()+5, c.begin());

/* swaps the first five element of


vector v by the elements of vector c */

for(vector<int>::iterator i = v.begin() ; i!= v.end() ; i++)


cout<< *i <" ";

cout<<endl;

for(vector<int>::iterator k = c.begin() ; k!= c.end() ; k++)


cout<<*k<<" ";
}

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>

using namespace std;

int main ()
{
int a[] = {1,5,4,9,8,6,1,3,5,4};
reverse(a, a+10);

/* reverse all the elements of the array a*/


/* now a is : 4,5,3,1,6,8,9,4,5,1 */

reverse(a, a+5);

/* reverse first 5 elements of the array a */


/* now a is : 6,1,3,5,4,8,9,4 */

vector<int> v(a, a+10);

reverse(v.begin(), v.end());

/* reverse the elements of the vector v */


/* vector is now 4,9,8,4,5,3,1,6 */
}

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>

using namespace std;

int main()
{
int values[] = {1,4,8,9,5,6,2,7,4,1};

vector<int> v1(values, values+10);


/* v1 is now 1,4,8,9,5,6,2,7,4,1 */

vector<int> v2;

v2.resize(v1.size()); // allocate size for v2

reverse_copy(v1.begin(), v1.end(), v2.begin());


/* copies elements of v1 in reverse order in 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>

using namespace std;

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 */

rotate(v.begin(), v.begin()+5, v.end());


/* now vector v is :6,9,2,1,5,9,8,4 */
}

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>

using namespace std;

bool cmp_function(int a , int b )


{
return a+b;
}

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,-,-,-,- */

/* - indicates that the elements are removed from the vector


and next elements are shifted to their position */

/* now it is pointing to the first occurrence of the “-“ in


the vector , i.e the position next to the last element (4) */

/* adjusting the size of vector v */

v.resize(distance(v.begin(),it));
/* resize the vector by the size returned by distance function,
which returns the distance between the two iterators */

/* vector v is now 10,5,9,6,4 */

/* using compare_function */

vector<int> v3(values, values+9);

it = unique(v3.begin(), v3.end(), cmp_function);


v3.resize(distance(v3.begin(), it));

/* removes copies the duplicate elements from v3*/


return 0;
}

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().

 unique_copy(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_copy(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>

using namespace std;

bool cmp_fuction(int a , int b )


{
return a+b;
}

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,-,-,-,- */

/* - indicates that the elements are removed from the vector


and next elements are shifted to their position */

/* now it is pointing to the first occurrence of the “-“


in the vector, i.e the position next to the last element (4) */

/* adjusting the size of vector v */

v.resize(distance(v.begin(), it));
/* resize the vector by the size returned by distance function,
which returns the distance between the two iterators */

/* vector v is now 10,5,9,6,4 */

/* using compare_function */

vector<int> v3(values,values+9),v4;
v4.resize(v3.size());

it = unique_copy(v3.begin(), v3.end(), v4.begin(), cmp_fuction);


v4.resize(distance(v4.begin(), it));

/* copies the unique elements from v3 to v4 */

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>

using namespace std;

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 );

/* now the vector v is 10,11,12,13,14,15,16,17,18,19 */


}

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>

using namespace std;

int myoperator(int a, int b )


{
return a*b;
}

int main()
{
vector<int> v;

for(int i = 0 ; i < 10; i++) {


v.push_back(i);
}

/* now vector v is : 0,1,2,3,4,5,6,7,8,9 */

int result;

accumulate(v.begin(), v.end(), result) ;

/* as no operator is specified, accumulate add all the elements


between v.begin() and v.end() and store the sum in result */

/* now result = 45 */

accumulate(v.begin(), v.end(), result, myoperator) ;

/* 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>

using namespace std;

int myoperator(int a, int b)


{
return a*b;
}

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());

partial_sum(v.begin(), v.end(), v2.begin());

/* now v2 is : 1,3,6,10,15 */
/* sum of the successive range in v.begin() and v.end() */

partial_sum(v.begin(), v.end(), v2.begin(), myoperator);

/* 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

max and min Method


max method's syntax is : max(object_type a, object_type b, compare_function)
This method returns the larger element of a and b. compare_function can be omitted. If there is no
compare_function used in max() then elements are compared with operator > by default.
compare_function is used to determine which one of the object is larger when the objects a and b
are non numeric type.

min method's syntax is : min(object_type a, object_type b, compare_function)


This method returns the smaller element of a and b. compare_function can be omitted. If there is
no compare_function used in min() then elements are compared with operator < by default.
compare_function is used to determine which one of the object is smaller when the objects a and b
are non numeric type.
Following is an example to demonstrate the usage of max() and min() methods.
#include<iostream>
#include<algorithm>

using namespace std;

/*compare function for strings*/


bool myMaxCompare(string a, string b)
{
return (a.size() > b.size());
}

bool myMinCompare(string a, string b)


{
return (a.size() > b.size());
}

int main()
{
int x=4, y=5;

cout << max(x,y); // prints 5


cout << min(x,y); // prints 4
cout << max(2.312, 5.434); // prints 5.434
cout << min(2.312, 5.434); // prints 2.312

string s = "smaller srting";


string t = "longer string---";

string s1 = max(s, t, myMaxCompare);


cout<< s1 <<endl; // prints longer string---

string s1 = min(s, t, myMinCompare);


cout<< s1 <<endl; // prints smaller string
}

max_element and min_element Method


max_element method's syntax is :
max_element(iterator first, iterator last, compare_function)
This method returns the largest element in the range [first, last]. compare_function can be omitted.
If there is no compare_function used in max_element() then elements are compared with operator >
by default. compare_function is used to determine which one of the object is larger when the
objects a and b are non numeric types.

min_element method's syntax is :


min_element(iterator first, iterator last, compare_function)
This method returns the smaller element in the range [first, last]. compare_function can be omitted.
If there is no compare_function used in min_element() then elements are compared with operator <
by default. compare_function is used to determine which one of the object is smaller when the
objects a and b are non numeric types.
Following is an example to demonstrate usage of max_element() and min_element() method.
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;

bool myMaxCompare(int a, int b)


{
return (a < b);
}

bool myMinCompare(int a, int b)


{
return (a < b);
}

int main()
{
int values[] = { 1,5,4,9,8,10,6,5,1};
vector<int> v(values,values+9);

cout<< *max_element(v.begin(), v.end());


/* prints 10 */

cout<< *min_element(v.begin(), v.end());


/* prints 1 */

/* using mycompare function */


cout<< *max_element(v.begin(), v.end(), myMaxCompare);
/* prints 10 */

cout<< *min_element(v.begin(), v.end(), myMinCompare);


/* prints 1 */
}
lexicographical_compare Method
The syntax for this method is :
lexicographical_compare(iterator first1, iterator last1, iterator first2, iterator last2)

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)

Following is a program to demonstrate its usage :


#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

bool myoperator(char a , char b)


{
return a > b;

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

minmax and minmax_element Method


minmax method's syntax is : minmax(object_type a ,object_type b)
This method returns a pair, where first element of the pair is the smaller element of a and b and the
second element of the pair is the larger element of a and b. If both, a and b are equal than minmax
returns a pair of <a,b>. minmax is available in C++ 11 and above only.
Following is an example to demonstrate usage of the minmax() method.
#include<iostream>
#include<algorithm>
#include<numeric>

using namespace std;

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 , */

/* minmax can also be used for number of elements */

p = minmax({2,6,5,4,9,8});
/* now p.first = 2 ( smaller element )
And p.second = 9 ( larger element ) */
}

minmax_element method's syntax is : minmax_element(iterator first, iterator last,


compare_function)
This method returns a pair of iterator where first element of the pair points to the smallest element in
the range [first,last] and second element of the pair points to the largest element in the range
[first,last].
Following is an example to demonstrate the usage of minmax_element().
#include<iostream>
#include<algorithm>
#include<array>
using namespace std;

int main ()
{
array<int,7> foo {3,7,2,9,5,8,6};

auto result = minmax_element(foo.begin(), foo.end());

// print result:
cout << "min is " << *result.first;
cout << "max is " << *result.second;
return 0;
}

next_permutation and prev_permutation Method


next_permutation method's syntax is :
next_permutation(iterator first ,iterator last)
This method arranges the elements in the range [first,last] in the next lexicographically larger
arrangement. For elements in range of length n, there are n!(factorial) possible ways in which the
elements can be arranged, each arrangement is called a permutation.

prev_permutation method's syntax is :


prev_permutation(iterator first, iterator last)
This method arranges the elements in the range [first,last] in the next lexicographically smaller
arrangement.
Following is an example to demonstrate usage of max_element() and min_element() method.
#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

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 */

vector<int> v(a, a+4);


/* v is : 1,2,4,3 */

next_permutation(v.begin(), v.end() );
/* now v is : 1,3,2,4 */

/* resetting a[] for prev_permutation */


int a[] = {1,2,3,4};

prev_permutation(a, a+4);
/* now a is 4,3,2,1 */

vector<int> v(a, a+4);


/* v is : 4,3,2,1 */
prev_permutation(v.begin(), v.end());
/* now v is : 4,3,1,2 */

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 {};

means B “is implemented in terms of” A.

o Public inheritance creates subtypes of the base type. If we have class B :


public A {}; then any B object is substituteable by its base calls object
(through means of pointers and references) so you can safely write
o A* aPointer = new B();

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();

// ERROR! compiler complains that the


// method is not accessible
beePointer->doSomething();
// ERROR! compiler complains that the
// conversion from B* to A* exists but
// is not accessible
A* aPointer = new B();
// ! for the following two the standard
// stipulates the behavior as undefined;
// the compiler should generate an error at least
// for the first one saying that B is not a
// polymorphic type
A* aPointer2 = dynamic_cast<A*>(beePointer);
A* aPointer3 = reinterpret_cast<A*>(beePointer);

6. Is the “friend” keyword really your friend?[sql_lall]


o The friend keyword provides a convenient way to let specific nonmember
functions or classes to access the private members of a class
o friends are part of the class interface and may appear anywhere in the class
(class access specifiers do not apply to friends); friends must be explicitly
declared in the declaration of the class; e.g., :
o class Friendly;
o
o // class that will be the friend
o class Friend
o {
o public:
o void doTheDew(Friendly& obj);
o };
o
o class Friendly
o {
o // friends: class and function; may appear
o // anywhere but it's
o // better to group them toghether;
o // the default private access specifier does
o // not affect friends
o friend class Friend;
o friend void friendAction(Friendly& obj);
o public:
o Friendly(){ };
o ~Friendly(){ };
o private:
o int friendlyInt;
o };
o
o // the methods in this class can access
o // private members of the class that declared
o // to accept this one as a friend
o void Friend :: doTheDew(Friendly& obj) {
o obj.friendlyInt = 1;
o }
o
o // notice how the friend function is defined
o // as any regular function
o void friendAction(Friendly& obj)
o {
o // access the private member
o if(1 == obj.friendlyInt)
o {
o obj.friendlyInt++;
o } else {
o obj.friendlyInt = 1;
o }
o }
o “friendship isn’t inherited, transitive or reciprocal,” that is, your father’s best
friend isn’t your friend; your best friend’s friend isn’t necessarily yours; if you
consider me your friend, I do not necessarily consider you my friend.
o Friends provide some degree of freedom in a class’ interface design. Also in
some situations friends are syntactically better, e.g., operator overloading –
binary infix arithmetic operators, a function that implements a set of
calculations (same algorithm) for two related classes, depending on both
(instead of duplicating the code, the function is declared a friend of both;
classic example is Matrix * Vector multiplication).
o And to really answer the question, yes, friend keyword is indeed our friend
but always “prefer member functions over nonmembers for operations that
need access to the representation.”[Stroustrup]
7. For a class MyFancyClass { }; what default methods will the compiler
generate?
o The default constructor with no parameters
o The destructor
o The copy constructor and the assignment operator
o All of those generated methods will be generated with the public access
specifier
o E.g. MyFancyClass{ }; would be equivalent to the following :
o class MyFancyClass
o {
o public:
o // default constructor
o MyFancyClass();
o // copy constructor
o MyFancyClass(const MyFancyClass&);
o // destructor
o ~MyFancyClass();
o
o
o // assignment operator
o MyFancyClass& operator=(const MyFancyClass&);
o };
o All of these methods are generated only if needed
o The default copy constructor and assignment operator perform memberwise
copy construction/assignment of the non-static data members of the class; if
references or constant data members are involved in the definition of the
class the assignment operator is not generated (you would have to define and
declare your own, if you want your objects to be assignable)
o I was living under the impression that the unary & (address of operator) is as
any built-in operator – works for built-in types; why should the built-in operator
know how to take the address of your home-brewed type? I thought that
there’s no coincidence that the “&” operator is also available for overloading
(as are +, -, >, < etc.) and it’s true is not so common to overload it, as you can
live with the one generated by the compiler that looks like the following:
o inline SomeClass* SomeClass::operator&()
o {
o return this;
o }
Thanks to bmerry for making me doubt what seemed the obvious. I found out the
following:
From the ISO C++ standard:
Clause 13.5/6 [over.oper] states that operator =, (unary) & and , (comma) have a
predefined meaning for each type. Clause 5.3.1/2 [expr.unary.op] describes the
meaning of the address-of operator. No special provisions are mode for class-type
objects (unlike in the description of the assignment expression). Clause 12/1
[special] lists all the special member functions, and states that these will be implicitly
declared if needed. The address-of operator is not in the list.
From Stroustrup’s The C++ Programming Language – Special 3rd Edition:
“Because of historical accident, the operators = (assignment), & (address-of), and ,
(sequencing) have predefined meanings when applied to class objects. These
predefined meanings can be made inaccessible to general users by making them
private:… Alternatively, they can be given new meanings by suitable definitions.”
From the second edition of Meyer’s Effective C++:
“A class declaring no operator& function(s) does NOT have them implicitly declared.
Rather, compilers use the built-in address-of operator whenever “&” is applied to an
object of that type. This behavior, in turn, is technically not an application of a global
operator& function. Rather, it is a use of a built-in operator.” In the errata
http://www.aristeia.com/BookErrata/ec++2e-errata_frames.html

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!

1. What are virtual functions?


o Virtual functions represent the mechanism through which C++ implements the OO
concept of polymorphism. Virtual functions allow the programmer to redefine in each
derived class functions from the base class with altered behavior so that you can call
the right function for the right object (allow to perform the right operation for an
object through only a pointer/reference to that object’s base class)
o A member function is declared virtual by preceding its declaration (not the definition)
with the virtual keyword
o class Shape
o {
o public:
o ...
o //a shape can be drawn in many ways
o virtual void draw(){ };
o };

“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)

class Rectangle : public Shape


{
public:
...
void draw() { };
};

class Square : public Rectangle


{
public:
...
void draw() { };
};
...

Shape* theShape = new Square();


// with the help of virtual functions
// a Square will be drawn and not
// a Rectangle or any other Shape
theShape->draw();
o Through virtual functions C++ achieves what is called late binding (dynamic binding
or runtime binding), that is actually connecting a function call to a function body at
runtime based on the type of the object and not at compilation time (static binding)
(**)
2. What is a virtual destructor and when would you use one?
o A virtual destructor is a class’ destructor conforming to the C++’s polymorphism
mechanism; by declaring the destructor virtual you ensure it is placed in the
VTABLE of the class and it will be called at proper times
o You make a class’ destructor virtual to ensure proper clean-up when the class is
supposed to be subclassed to form a hierarchy and you want to delete a derived object
thorough a pointer to it (the base class)
o E.g. :
o #include <vector>
o #include <iostream>
o
o using namespace std;
o
o class Base
o {
o public:
o Base(const char* name);
o // warning! the destructor should be virtual
o ~Base();
o
o virtual void doStuff();
o private:
o const char* m_name;
o };
o
o Base :: Base(const char* name) : m_name(name)
o {
o
o }
o
o Base :: ~Base()
o {
o
o }
o
o
o
o void Base :: doStuff()
o {
o cout << "Doing stuff in Base" << endl;
o }
o
o
o
o class Derived : public Base
o {
o public:
o Derived(const char* name);
o ~Derived();
o
o virtual void doStuff();
o private:
o vector<int>* m_charCodes;
o };
o
o Derived :: Derived(const char* name) : Base(name)
o {
o m_charCodes = new vector<int>;
o }
o
o Derived :: ~Derived()
o {
o delete m_charCodes;
o }
o
o void Derived :: doStuff()
o {
o cout << "Doing stuff in Derived" << endl;
o }
o
o int main(int argc, char* argv[])
o {
o // assign the derived class object pointer to
o // the base class pointer
o char* theName = "Some fancy name";
o Base* b = new Derived(theName);
o
o // do some computations and then delete the
o // pointer
o delete b;
o return 0;
o }

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:

[Created using the TopCoder UML Tool]

// 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();
};

// Factory Method implementation


void Resume :: CreatePages()
{
thePageList.push_back(new SkillsPage());
thePageList.push_back(new ExperiencePage());
}

// ConcreteCreator
class Report : public Document
{
public:
// Factory Method implementation
void CreatePages();
};

// Factory Method implementation


void Report :: CreatePages()
{
thePageList.push_back(new TableOfContentsPage());
thePageList.push_back(new IntroductionPage());
}

int main(int argc, char* argv[])


{
// Note: constructors call Factory Method
vector<Document*> documents(2);
documents[0] = new Resume();
documents[1] = new Report();

return 0;
}

10. What is RAII?


o RAII – Resource Acquisition Is Initialization – is a C++ technique (but not limited to
the C++ language) that combines acquisition and release of resources with
initialization and uninitialization of variables
o E.g. :
o // this is a hypothetic LogFile class using an
o // hypothetic File class just for the illustration
o // of the technique
o class LogFile
o {
o public:
o LogFile(const char*);
o ~LogFile();
o
o void write(const char*);
o private:
o File* m_file;
o };
o
o LogFile :: LogFile(const char* fileName) :
o // ! acquisition and initialization
o m_file(OpenFile(fileName))
o {
o if(NULL == m_file)
o {
o throw FailedOpenException();
o }
o }
o
o LogFile :: ~LogFile()
o {
o // ! release and uninitialization
o CloseFile(m_file);
o }
o
o void LogFile :: write(const char* logLine)
o {
o WriteFile(m_file, logLine);
o }
o
o // a hypothetical usage example
o void SomeClass :: someMethod()
o {
o LogFile log("log.tx");
o log.write("I've been logged!");
o
o // !exceptions can be thrown without
o // worrying about closing the log file
o // or leaking the file resource
o if(...)
o {
o throw SomeException();
o }
o }
o Without RAII each usage of the LogFile class would be also combined with the
explicit management of the File resource. Also in the presence of exceptions you
would have to be careful and clean-up after yourself, thing that is taken care of with
the proper usage of RAII as illustrated in the example above
o RAII is best used with languages that call the destructor for local objects when they
go out of scope (implicit support of the technique) like C++. In other languages, like
Java & C#, that rely on the garbage collector to destruct local objects, you need
finalization routines (e.g. try-finally blocks) to properly use RAII
o Real usage examples of the technique are the C++ Standard Library’s file streams
classes and STL’s auto_ptr class (to name just very, very few)

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();
};

void Fred::f(int i) throw()


{ cout << "Fred::f(int); i=" << i << ’\n’; }
void Fred::g(int i) throw()
{ cout << "Fred::g(int); i=" << i << ’\n’; }
void Fred::h(int i) throw()
{ cout << "Fred::h(int); i=" << i << ’\n’; }

typedef void(Fred::*FredMemberPtr)(int);

void sample(Fred& x, FredMemberPtr p) throw()


{ (x.*p)(42); } // If p is &Fred::g, this is the same as x.g(42)
int main()
{
FredMemberPtr p = &Fred::g;
Fred x;
sample(x, p);
}
The output of this program is as follows.
Fred::g(int); i=42

Potrebbero piacerti anche