Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

C++ Assignments 1-11

Download as pdf or txt
Download as pdf or txt
You are on page 1of 173

Programming in Modern C++: Assignment Week 1

Total Marks : 25

Partha Pratim Das


Department of Computer Science and Engineering
Indian Institute of Technology Kharagpur, Kharagpur – 721302
partha.p.das@gmail.com

January 15, 2024

Question 1
Consider the following program. [MCQ, Marks 2]

#include <iostream>
#include <cstring>
#include <stack>

using namespace std;

int main(){
char str[10] = "COMPUTER";
stack<char> s1, s2;
int i;
for(i = 0; i < strlen(str)/2; i++)
s1.push(str[i]);
for(; i < strlen(str); i++)
s2.push(str[i]);

while (!s1.empty()) {
s2.push(s1.top()); s1.pop();
}
while (!s2.empty()) {
cout << s2.top(); s2.pop();
}
return 0;
}

What will be the output?

a) COMPUTER

b) RETUPMOC

c) UTERCOMP

d) COMPRETU

1
Answer: d)
Explanation:
The stack s1 stores {P, M, O, C} and the stack s2 stores {R, E, T, U}. Then the elements of
s1 also pushed into s2 as {C, O, M, P, R, E, T, U}. Thus, when we finally pop and print the
elements from s2, the output would be COMPRETU.

2
Question 2
Which of the following is NOT a container adapter? [MCQ, Mark 1]

a) stack

b) queue

c) deque

d) priority queue

Answer: c)
Explanation:
All of them are sequence containers.
However, stack, queue and prority queue are the sequence containers adapted with specific
protocols of access like LIFO, FIFO, Priority and known as container adaptors.

3
Question 3
Consider the following code segment. [MCQ, Marks 2]

#include <iostream>
#include <algorithm>
using namespace std;
int main() {
char data[] = {’a’, ’b’, ’c’, ’d’, ’e’};
char key = ’d’;
if(binary_search(__________________)) //LINE-1
cout << "found";
else
cout << "not found";
return 0;
}

Identify the appropriate option/s to fill in the blank LINE-1 such that output becomes found.

a) &data[0], &data[5], key

b) data, data+5, key

c) data, key, data+5

d) &data[0], &key, &data[5]

Answer: a), b)
Explanation:
binary search(.) function takes 3 parameters. The first two parameters are staring and
ending address of the array, and the third parameter is the key to search. Hence, the correct
option is a) and b).

4
Question 4
Consider the following code segment. [MCQ, Marks 2]

#include <iostream>
#include <algorithm>
using namespace std;

void modify(int *arr){


rotate(arr, arr + 3, arr + 5);
rotate(arr, arr + 2, arr + 4);
}

int main() {
int iarr[5];
for(int i = 0; i < 5; i++)
*(iarr + i) = i + 1;

modify(iarr);
for (int i = 0; i < 5; ++i)
cout << *(iarr + i) << " ";
return 0;
}

What will be the output?

a) 1 2 3 4 5

b) 1 2 4 5 3

c) 4 5 1 2 3

d) 2 3 4 5 1

Answer: b)
Explanation:
rotate(first, middle, last) rotates the order of the elements in the range [f irst, last], in
such a way that the element pointed by middle becomes the new first element.
rotate(arr, arr + 3, arr + 5) makes the order as 4 5 1 2 3.
rotate(arr, arr + 2, arr + 4) makes the order as 1 2 4 5 3.

5
Question 5
Consider the following code segment. [MCQ, Marks 2]

#include <iostream>
#include <vector>
int main() {
std::vector<int> cVec(3, -1);
for(int i = 0; i < 3; i++)
cVec[i] = (i + 1) * 10;
cVec.resize(3);
cVec.resize(3, 110);
for(int i = 0; i < 3; i++)
cVec.push_back((i + 1) * 20);
for(int i = 0; i < cVec.size(); i++)
std::cout << cVec[i] << " ";
return 0;
}

What will be the output?

a) 10 20 30 20 40 60

b) -1 -1 -1 10 20 30 20 40 60

c) -1 -1 -1 10 20 30 0 0 0 20 40 60

d) 10 20 30

Answer: a)
Explanation:
Vectors are similar to dynamic arrays having the ability to resize itself automatically when an
element is inserted or deleted, with their storage being handled automatically by the container.
The statements and the states of the vector are as follows:

std::vector<int> cVec(3, -1); => [-1 -1 -1],

for(int i = 0; i < 3; i++)}


cVec[i] = (i + 1) * 10; => [10 20 30]

cVec.resize(3); => [10 20 30]


Also, cVec.resize(3, 110) => [10,20,30]

for(int i = 0; i < 3; i++)}


cVec.push_back((i + 1) * 20); => [10 20 30 20 40 60]}

6
Question 6
Consider the following code segment. [MSQ, Marks 2]

#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int iarr[] = {10, 20, 50, 40, 10, 50};
rotate(&iarr[0], &iarr[2], &iarr[6]);
___________________________; //LINE-1
for(int i = 0; i < 4; ++i)
cout << iarr[i] << " ";
return 0;
}

Fill in the blank at LINE-1 with appropriate option/s such that the output is: 40 10 10 20

a) remove(&iarr[0], &iarr[6], 50)

b) remove(&iarr[0], &iarr[5], 50)

c) remove(iarr, iarr + 6, 50)

d) remove(iarr, iarr + 6, iarr[5])

Answer: a), c)
Explanation:
After execution of rotate(&iarr[0], &iarr[2], &iarr[6]), the contents of array becomes
50 40 10 50 10 20 .
For the desired output, the value 50 has to be removed, which can be done using the statement:
remove(&iarr[0], &iarr[6], 50)
or remove(iarr, iarr + 6, 50)

7
Question 7
Consider the following code segment. [MCQ, Marks 2]

#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int idata[] = { 1, 2, 3, 4, 5 };
int n = sizeof(idata) / sizeof(*idata);
for (int i = 0; i < n/2; i++) {
int temp = idata[i];
replace(idata, idata + 5, temp, *(idata + n - i - 1));
replace(idata + i + 1, idata + 5, idata[n - i - 1], temp);
}
for (int i = 0; i < 5; ++i)
cout << idata[i] << " ";
return 0;
}

What will be the output?

a) 3 2 1 2 3

b) 1 2 3 2 1

c) 5 4 3 4 5

d) 5 4 3 2 1

Answer: d)
Explanation:
In the first iteration,
the statement: replace(idata, idata + 5, temp, *(idata + n - i - 1));
replaces the left-most element (left-most element is saved as temp) with the right-most element,
and the statement: replace(idata + i + 1, idata + 5, idata[n - i - 1], temp);
replaces the right-most element with temp.
This will be continued till the middle of the array. Thus, it reverses the array.

8
Question 8
Consider the following code segment. [MSQ, Marks 2]

#include <iostream>
#include <string>
using namespace std;

int main(void) {
string str1 = "Modern ";
string str2 = "C++";
_____________________; //LINE-1
cout << str1;
return 0;
}

Choose the appropriate option to fill in the blank at LINE-1, such that the output of the code
would be: Modern C++.

a) str1 += str2

b) strcat(str1, str2)

c) str1.append(str2)

d) str1.insert(str2)

Answer: a), c)
Explanation:
In C++, operator+= and append(·) append the strings. Please note that strcat(·) is a C
function, and required inclusion of cstring. The function insert(·) is used to insert a string
in another string at a given position.

9
Question 9
Consider the following code segment. [MCQ, Marks 2]

#include <iostream>
#include <algorithm>
using namespace std;

int main() {
int iArr[] = {40, 50, 10, 30, 20};
sort (iArr, iArr + 4);
for (int i = 0; i < 5; i++)
cout << *(iArr + i) << " ";
return 0;
}

What will be the output?

a) 10 20 30 40 50

b) 10 30 40 50 20

c) 50 40 30 20 10

d) 50 40 30 10 20

Answer: b)
Explanation:
Since in the sort(·) function, the end is set after the 4th element, it sorts from the first
position to fourth position, leaving the last element of the array. Thus, the output is 10 30
40 50 20.

10
Programming Questions

Question 1
Consider the program below.

• Fill in the blank at LINE-1 to include appropriate header file to utilize sqrt(·) function.

• Fill
p in the blank at LINE-2 to compute the length between two points p1 and p2 as
(p1.y − p2.y)2 + (p1.x − p2.x)2 .

The program must satisfy the given test cases. Marks: 3

#include <iostream>
__________________ //LINE-1
using namespace std;
struct point{
int x, y;
};

double get_len(point p1, point p2){


return _____________________; //LINE-2
}

int main() {
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
point p1, p2;
p1.x = x1;
p1.y = y1;
p2.x = x2;
p2.y = y2;
cout << get_len(p1, p2);
return 0;
}

Public 1
Input: 10 10 20 20
Output: 14.1421

Public 2
Input: 10 20 40 20
Output: 30

Private
Input: 20 40 60 10
Output: 50

11
Answer:
LINE-1: #include <cmath>
LINE-2: sqrt((p1.y - p2.y) * (p1.y - p2.y) + (p1.x - p2.x) * (p1.x - p2.x))
Explanation:
The C library math.h can be included in C++ program as
#include <cmath>
At LINE-2, the formula to compute the distance between two points can be implemented as:
sqrt((p1.y - p2.y) * (p1.y - p2.y) + (p1.x - p2.x) * (p1.x - p2.x))

12
Question 2
Consider the following program.

• Fill in the blank at LINE-1 with the appropriate header of max str( ).

• Fill in the blank at LINE-2 with the appropriate statements such that the string array
can be sorted in descending order.

The program must satisfy the sample input and output. Marks: 3

#include <iostream>
#include <algorithm>
using namespace std;

____________________________ { //LINE-1
_________________; //LINE-2
}

int main() {
std::string words[5], word;
for(int i = 0; i < 5; i++){
cin >> word;
words[i] = word;
}
sort(words, words + 5, max_str);
for (int i = 0; i < 5; i++)
cout << words[i] << " ";
return 0;
}

Public 1
Input: Lion Tiger Bear Hippo Bull
Output: Tiger Lion Hippo Bull Bear

Public 2
Input: Wale Fox Deer Frog Crab
Output: Wale Frog Fox Deer Crab

Private
Input: Dog Cat Bat Pig Cow
Output: Pig Dog Cow Cat Bat

Answer:
LINE-1: bool max str (string s1, string s2)
LINE-2: return (s1 > s2)
Explanation:
At LINE-1, define function header as:
bool max str (string s1, string s2)
At LINE-2, define the return statement for sorting in descending order as:
return (s1 > s2);

13
Question 3
Consider the following program.

• Fill in the blanks at LINE-1 to add each string to the stack.

• Fill in the blanks at LINE-2 to print the element at the top of the stack.

• Fill in the blanks at LINE-3 to remove the element at the top of the stack.

The program must satisfy the sample input and output. Marks: 3

#include <iostream>
#include <stack>
#include <vector>

void printReverseOrder(std::vector<std::string> words){


std::stack<std::string> s;

for(int i = 0; i < words.size(); i++)


_____________________; //LINE-1
while(!s.empty()){
std::cout << __________ << " "; //LINE-1
_____________________; //LINE-3
}
}
int main() {
int n;
std::cin >> n;
std::vector<std::string> vec;
for(int i = 0; i < n; i++){
std::string wd;
std::cin >> wd;
vec.push_back(wd);
}
printReverseOrder(vec);
return 0;
}

Public 1
Input: 4 Mercury Venus Earth Mars
Output: Mars Earth Venus Mercury

Public 2
Input: 5 Arctic Antarctic Atlantic Pacific Indian
Output: Indian Pacific Atlantic Antarctic Arctic

Private
Input: 7 Cow Sheep Dog Goat Horse Mouse Ox
Output: Ox Mouse Horse Goat Dog Sheep Cow

14
Answer:
LINE-1: s.push(words[i])
LINE-2: s.top()
LINE-3: s.pop()
Explanation:
At LINE-1, each element can be added to the stack as:
s.push(words[i])
At LINE-2, the element at the top of the stack can be displayed as:
std::cout << s.top() << " ";
At LINE-3, the element at the top of the stack can be removed as:
LINE-3: s.pop()

15
Programming in Modern C++: Assignment Week 2
Total Marks : 25

Partha Pratim Das


Department of Computer Science and Engineering
Indian Institute of Technology Kharagpur, Kharagpur – 721302
partha.p.das@gmail.com

January 25, 2024

Question 1
Consider the following program. [MCQ, Marks 2]

#include <iostream>
using namespace std;
int add(int n1 = 0) { return n1; }
int add(int n1 = 0, int n2 = 0) { return n1 + n2 - 1;}
int add(int n1 = 0, char c1 = ’a’){ return n1 + c1 - 1; }
int add(char c1 = ’z’, int n1 = 0) { return n1 + c1 ; }
int main() {
int c = add(10, 5);
cout << c << endl;
return 0;
}

What will be the output?

a) 15

b) 14

c) 62

d) Compilation error: call of overload "add(int, int)" is ambiguous

Answer: b)
Explanation:
The call add(10, 5) invokes the function int add(int, int) which returns the value 14.
Hence, the correct answer is 14.

1
Question 2
Consider the following program. [MCQ, Mark 2]

#include <iostream>
using namespace std;
#define DOUBLE1(x) x + x
#define DOUBLE2(x) 2 * x
int main() {
int a=2;
cout << DOUBLE1(a++) << " " << DOUBLE2(a++) << endl;
return 0;
}

What will be the output (Consider right to left execution of the cout statement)?

a) 7 4

b) 8 4

c) 4 4

d) 7 6

Answer: a)
Explanation:
In a macro call, the arguments get substituted blindly, and then evaluated. So, the evaluation
of the cout expression will be done as follows:

cout << DOUBLE1(a++) << " " << DOUBLE2(a++) << endl;
cout << a++ + a++ << " " << 2 * a++ << endl;
cout << a++ + a++ << " " << 2 * 2 << endl; //(a becomes 3 after substitution)
cout << 4 + 3 << " " << 4 << endl; //(a becomes 5 after substitution)
cout << 7 << " " << 4 << endl;

Hence, the output is 7 4.

2
Question 3
Consider the following code segment. [MCQ, Marks 2]

#include <iostream>
using namespace std;
int& func(int& x) { //LINE-1
return x = x*2;
}
int main() {
int a = 3, b = 4;
int& c = func(a);
cout << a << " " << c << " ";
func(a) = b;
cout << a << " " << c;
return 0;
}

What will be the output?

a) 6 6 2 2

b) 6 8 4 2

c) 6 6 4 4

d) 8 6 4 4

Answer: c)
Explanation:
The change in the formal parameter x is reflected on the actual variable a because it is passed
as a reference. However, not as a constant reference, since the formal parameter is modified
within the function. So, first cout statement will print 6 6. The statement int& c = func(a);
requires the return type to be a reference type. This statement will modify the value of a and
c with the value of b. Hence, c) is the correct option.

3
Question 4
Consider the following code segment. [MCQ, Marks 2]

#include <iostream>
using namespace std;
void compute(int x1, int x2, ___________, __________){ //LINE-1
x3 = x1 + x2;
*x4 = x1 * x3;
}
int main(){
int a = 10, b = 20, c = 1, d = 1;
compute(a, b, c, &d); //LINE-2
cout << c << ", ";
cout << d;
return 0;
}

Fill in the blank at LINE-1 so that the program will print 1, 300.

a) int x3, int x4

b) int &x3, int* x4

c) int x3, int& x4

d) int x3, int* x4

Answer: d)
Explanation:
Since the changes made in x3, *x4 in function compute() need to be reflected in the variables
c, d in main(), these are either pass-by-reference or pass-by-address.
From call at LINE-1, it can be observed that c is passed-by-value and d is passed-by-address.
Thus, the header of compute() must be:
void compute(int x1, int x2, int x3, int* x4)

4
Question 5
Consider the following code segment. [MSQ, Marks 2]

#include <iostream>
using namespace std;
int main(){
const int &x; //LINE-1
x = 10; //LINE-2
cout << x;
return 0;
}

What will be the output?

a) 0

b) 10

c) Compilation error at LINE-1: ’x’ declared as reference but not initialized

d) Compilation error at LINE-2: assignment of read only reference x

Answer: c), d)
Explanation:
When a reference variable is declared as const, that should be initialized at the time of
declaration. At LINE-1, x is declared as constant but is not initialized at the time of declaration.
Hence, this line will give compilation error.
Constant variable cannot be reassigned after declaration. Since we try to change the value of
x at LINE-2 (after declaration) which gives another error.
Hence, correct options are c) and d).

5
Question 6
Consider the following code segment. [MSQ, Marks 2]

#include <iostream>
using namespace std;
int main(){
int x = 2, y = 7;
______ int &r = ++x + ++y; //LINE-1
cout << r;
return 0;
}

Fill in the blank at LINE-1 with appropriate option/s such that the output is: 11

a) const

b) volatile

c) static

d) inline

Answer: a)
Explanation:
The result of expression ++x + ++y is assigned to the reference variable r. The result is stored
in a temporary address which is referred by the variable r. Hence, r should be declared as
constant.
Intentionally made as MSQ

6
Question 7
Consider the following code segment. [MSQ, Marks 2]

#include <iostream>
#include<stdlib.h>
using namespace std;
int main(){
char *x = ______________; //LINE-1
cout << *x;
free(x);
return 0;
}

Fill in the blank at LINE-1 so that the program will print a.

a) (char*)malloc(10*sizeof(char))

b) new char(’a’)

c) new char(97)

d) new char[97]

Answer: b), c)
Explanation:
The pointer variable x should be assigned with character type memory and should be initialized
with ’a’ or ASCII value of ’a’ (i.e. 97) to get the desired output. Hence, the correct option
are b) and c).

7
Question 8
Consider the following code segment. [MSQ, Marks 2]

#include <iostream>
using namespace std;
int main(){
int n = 97;
const char *p = &n; //LINE-1
*p = ’x’; //LINE-2
cout << n;
return 0;
}

What will be the output(s)/error(s)?

a) 97

b) 120

c) Error at LINE-1: cannot convert int* to const char* in initialization

d) Error at LINE-2: assignment of read-only location *p

Answer: c), d)
Explanation:
The pointer variable p is declared as pointer to constant char, which restricts any modification
of value at the location where p points to. Since at LINE-1, we attempt to change the value
of the pointee or *p using integer variable reference, it gives a compilation error. Moreover, at
LINE-2, we attempt to change the pointee again with a constant character, which also gives
compilation error.

8
Question 9
Consider the following function prototypes of overloaded function func(). [MCQ, Marks 2]

1. int func(int , char* = 0);


2. double func(double = 0, double = 0);
3. float func(float, float, char* = 0);
4. float func(float n);
5. int func(int n1 = 0, int n2 = 0, int n3 = 0);

Which functions will be invoked for the call func(2.1, 3.7f)?

a) 2, 3, 5

b) 2, 3

c) 2

d) 1, 2

Answer: a)
Explanation:
Prototype-1: since the second argument 3.7f of float type does not matches with char*. Thus,
it does not match with the call.
Prototype-2: since the arguments type float upcasted to type double, it matches with the call.
Prototype-3: since the third formal argument is optional, it is a exact match with the call.
Prototype-4: since the number of arguments for the caller and callee are not the same, it does
not match with the call.
Prototype-5: since the third formal argument is optional and the actual arguments can be
implicitly casted to the formal argument types, it matches with the call.

9
Programming Questions

Question 1
Consider the program below.

• Fill in the blank at LINE-1 with an appropriate statement.

The program must satisfy the given test cases. Marks: 3

#include <iostream>
using namespace std;
#define THRICE(X) ________________ //LINE-1
int main(){
int n;
cin >> n;
cout << THRICE(n+1);
return 0;
}

Public 1
Input: 3
Output: 16

Public 2
Input: 5
Output: 36

Private
Input: 2
Output: 9

Answer:
LINE-1: (X) * X * X
Explanation:
If we observe the test cases, the definition of macro must be
#define THRICE(X) (X) * X * X
THRICE(3+1) = (3 + 1) * 3 + 1 * 3 + 1 = 4*3 + 1*3 + 1 = 16
THRICE(5+1) = (5 + 1) * 5 + 1 * 5 + 1 = 6*5 + 1*5 + 1 = 36

10
Question 2
Consider the following program.

• Fill in the blank at LINE-1 with appropriate formal arguments list.

• Fill in the blank at LINE-2 with the appropriate return statement.

The program must satisfy the sample input and output. Marks: 3

#include <iostream>
using namespace std;
int sqr(_______________) { // LINE-1
return ________; // LINE-2
}
int main() {
int x, y;
cin >> x >> y;
cout << sqr(x + y);
return 0;
}

Public 1
Input: 2 5
Output: 49

Public 2
Input: -8 5
Output: 9

Private
Input: -4 -2
Output: 36

Answer:
LINE-1: const int& x
LINE-2: x * x
Explanation:
The function call is made with an argument which is a constant expression. As the function
is called with a call-by-reference strategy, and actually an expression (x+y) is passed, the
argument should be constant in nature. So, LINE-1 should be filled as const int &x. The
function gives a square value as output. So LINE-2 should be filled as x*x.

11
Question 3
Consider the following program.

• Fill in the blanks at LINE-1 with appropriate function header

The program must satisfy the sample input and output. Marks: 3

#include <iostream>
#include <string>
using namespace std;
________________________________ { // LINE-1
int r = b + 10 * a;
cout << r;
}
int main() {
int p, q;
cin >> p >> q;
print(p, q);
return 0;
}

Public 1
Input: 4 1
Output: 41

Public 2
Input: 5
Output: 50

Private
Input: 7 4
Output: 74

Answer:
LINE-1: void print(int a, int b = 0)
Explanation:
The function header should have two parameters. The second parameter should have the
default value 0. So, LINE-1 can be filled with
void print(int a, int b = 0)

12
Programming in Modern C++: Assignment Week 3
Total Marks : 25

Partha Pratim Das


Department of Computer Science and Engineering
Indian Institute of Technology Kharagpur, Kharagpur – 721302
partha.p.das@gmail.com

February 1, 2024

Question 1
Consider the following program. [MSQ, Marks 2]

#include<iostream>
using namespace std;

class Check{
int x1 = 1;
public:
int x2 = 2;
int get_x1(){ return x1; }
int get_x2(){ return x2; }
};

int main(){
Check t;
int a, b;
a = t.x1; //LINE-1
b = t.x2; //LINE-2
a = t.get_x1(); //LINE-3
b = t.get_x2(); //LINE-4
return 0;
}

Which function call/s will generate error/s?

a) LINE-1

b) LINE-2

c) LINE-3

d) LINE-4

Answer: a)
Explanation:
At LINE-1, main() function is accessing the private data member using object t which will
generate an error.

1
At LINE-2, public member is being accessed using object t which is fine.
At LINE-3 and LINE-4, public functions are called using object of the class which will not
generate any error.
This question is intentionally made as MSQ

2
Question 2
Consider the following program. [MCQ, Mark 2]

#include <iostream>
using namespace std;
class Check{
public:
Check() { cout << "Default" << endl; }
Check(int x=0) { cout << "Parameterized" << endl; }
};

int main(){
Check m1;
return 0;
}

What will be the output/error?

a) Default

b) Parameterized

c) Default
Parameterized

d) Compilation error: call of overload ’Check()’ is ambiguous

Answer: d)
Explanation:
The program contains an ambiguous definition of Check constructor where the default con-
structor and parameterized constructor with default parameter make ambiguity in creating
objects. Hence, the program will give a compilation error.

3
Question 3
Consider the following code segment. [MCQ, Marks 2]

#include<iostream>
using namespace std;
class Line {
int _sp;
int _ep;
Line(int x, int y) {
_sp = x;
_ep = y;
cout << _sp << " " << _ep;
}
};
int main() {
Line l(1, 9);
return 0;
}

What will be the output/error?

a) 1 9

b) 9 1

c) Compilation error: constructor is private

d) Compilation error: no default constructor

Answer: c)
Explanation:
The parameterized constructor Line(int x, int y) is private by default, so it cannot be
accessed by from main() function. Hence option c) is correct.

4
Question 4
Consider the following code segment. [MCQ, Marks 2]

#include <iostream>
using namespace std;
class CharSeq {
char x, y;
public:
CharSeq(char _x, char _y) : x(_x), y(_y) { }
CharSeq(CharSeq &c) : x(c.x), y(c.y){ }
void change(CharSeq *new_c) { this = new_c; }
void show() { cout << x << ", " << y << endl; }
};
int main() {
CharSeq c1(’a’, ’c’);
CharSeq c2(’o’, ’k’);
CharSeq c3(c1);
c3.change(&c2);
c3.show();
return 0;
}

What will be the output/error?

a) a, c

b) o, k

c) Compilation Error: private data members are inaccessible

d) Compilation Error: lvalue required as left operand of assignment

Answer: d)
Explanation:
In the function change(&c2), the statement
this = new c;
attempts an assignment to this. Since this is a constant pointer (CharSeq * const), it
cannot be changed and the error occurs during compilation.

5
Question 5
Consider the following code segment. [MCQ, Marks 2]

#include<iostream>
using namespace std;
class instance{
int i;
public:
instance(int i_= 0) : i(i_){ cout << i << " "; }
~instance() { cout << i << " "; }
};
instance obj1(2); //LINE-1
int main(){
instance *pObj = new instance(1); //LINE-2
instance obj2(3); //LINE-3
{
instance obj3(4); //LINE-4
delete pObj; //LINE-5
} //LINE-6
return 0;
} //LINE-7

What will be the output?

a) 2 1 3 4 1 4 3 2

b) 2 1 3 4 4 3 1 2

c) 1 2 3 4 1 4 3 2

d) 1 2 3 4 4 3 2 1

Answer: a)
Explanation:
The object (obj1) definition at LINE-1 have a global scope, so this object will be created even
before the main() function starts. It calls the constructor and prints 2.
Then, within main(), another object gets instantiated at LINE-2, and it calls the constructor
and prints 1.
At LINE-3, an object obj2 gets instantiated, which calls the constructor and prints 3.
At LINE-4, an object obj3 gets instantiated within a block scope, and calls constructor and it
prints 4.
At LINE-5, object pObj (which was created at LINE-2 gets deleted, so it calls the destructor
and prints 1.
At LINE-6, the block scope ends. Thus the local object obj3 (which was created at LINE-4
gets deleted. It calls the destructor and prints 4.
At LINE-7, the scope of main() function ends. Thus the local object obj2 (which was created
at LINE-2 gets deleted. It calls the destructor and prints 3.
At the end of the program, the object obj1 having global scope gets deleted. It calls the
destructor and prints 2.

6
Question 6
Consider the following code segment. [MCQ, Marks 2]

#include<iostream>
using namespace std;
int gdata = 10;
class myClass{
int mdata;
public:
myClass(int mdata_ = 0) : mdata(++mdata_) { ++gdata; } //LINE-1
~myClass(){ mdata = 0; gdata--; }
void print(){ cout << mdata << ", " << gdata << endl; }
};
void func(){
myClass ob;
ob.print();
}
int main(){
myClass ob;
func();
ob.print();
return 0;
}

What will be the output?

a) 1, 11
0, 10

b) 1, 11
0, 12

c) 1, 12
1, 11

d) 1, 12
0, 11

Answer: c)
Explanation:
The statement myClass ob; in main(), calls the constructor at LINE-1 which makes mdata
= 1 and gdata = 11.
Then the statement myClass ob; in func(), calls the constructor at LINE-1 which makes
mdata = 1 and gdata = 12.
Then the statement ob.print(); in func() prints mdata = 1, gdata = 12. As the function
func() returns, the destructor for local object ob would be called, which makes mdata = 0
and gdata = 11.
Finally, the statement ob.print(); in main() prints mdata = 1, gdata = 11.

7
Question 7
Consider the following code segment. [MSQ, Marks 2]

#include <iostream>
using namespace std;
class Student {
int roll, marks;
string name;
public:
Student(int _roll, string _name, int _marks)
: roll(_roll), name(_name), marks(_marks){}
void incr_marks(){ ______________; } //LINE-1
void show(){ cout << roll << " : " << name << " : " << marks; }
};
int main() {
Student s(10, "Ram", 85);
s.incr_marks();
s.show();
return 0;
}

Fill in the blank at LINE-1 such that the output is 10 : Ram : 86.

a) marks++

b) this->marks++

c) this.marks++

d) this->(++marks)

Answer: a), b)
Explanation:
To increment the data-member marks, LINE-1 can be filled by ++marks.
The statement this->marks++ is also correct.
Since this is a pointer, option c) is incorrect.
-> operator is used to access a data-member of a given class. But (++marks) is not a data-
member. Thus option d) is also incorrect.

8
Question 8
Consider the following code segment. [MCQ, Marks 2]

#include <iostream>
using namespace std;
class myClass{
private:
double d;
public:
myClass() : d(0.0) { cout << "myClass() "; }
myClass(double _d) : d(_d) { cout << "myClass(double) ";}
myClass(const myClass& _od) : d(_od.d) { cout << "myClass(myClass&) ";}
~myClass() { cout << d << " "; }
};
int main(){
myClass d1(1.2); //LINE-1
myClass d2(); //LINE-2
myClass d3 = 2.3; //LINE-3
myClass d4 = d3; //LINE-4
return 0;
}

What will be the output/error?

a) myClass(double) myClass() myClass(double) myClass(myClass&) 2.3 2.3 1.2

b) myClass(double) myClass(double) myClass(myClass&) 2.3 2.3 1.2

c) myClass(double) myClass() myClass(double) myClass(myClass&) 2.3 2.3 0.0 1.2

d) Compilation error: data members are private

Answer: b)
Explanation:
The statement at LINE-1 calls the parameterized constructor, initialize d = 1.2 and prints
myClass(double).
The statement at LINE-2 though legal, does not create an object.
The statement at LINE-3 calls the parameterized constructor, initialize d = 2.3 and prints
myClass(double).
The statement at LINE-4 calls the copy constructor, initialize d = 2.3 and prints myClass(myClass&).
As the program falls to the end, the destructors for the objects will be invoked in the reverse
order of their creations and print 2.3 2.3 1.2.

9
Question 9
Consider the following code segment. [MCQ, Marks 2]

#include<iostream>
using namespace std;
class Pointer {
int _______________; //LINE-1: Declare the data members
public:
Pointer(int a, int b, int c) : x(seta(a)), y(setb(b)), z(setc(c)){ }
int* seta(int a){
cout << a;
return (new int(a));
}
int* setb(int b){
cout << b;
return (new int(b));
}
int* setc(int c){
cout << c;
return (new int(c));
}
};
int main() {
Pointer p(1,0,2);
return 0;
}

Fill in the blank at LINE-1 such that the output is 012.

a) *y, *z, *x

b) *x, *y, *z

c) *y, *x, *z

d) *z, *x, *y

Answer: c)
Explanation:
The order of invocation to initialization-list function take place as per the order of the data
members declared in the class declaration.

10
Programming Questions

Question 1
Consider the program below.

• Fill in the blank at LINE-1 to complete the parameterized constructor.

• Fill in the blank at LINE-2 to complete the copy constructor.

• Fill in the blank at LINE-3 to complete the appropriate function header.

The program must satisfy the given test cases. Marks: 3

#include<iostream>
#include<cmath>
using namespace std;
class Complex_num{
const int x,y;
public:
Complex_num(int _x=0, int _y=0) : ________________ {} //LINE-1
Complex_num(const Complex_num& c) : _________________ {} //LINE-2
____________________________________{
return Complex_num(x+c.x, y+c.y); //LINE-3
}
void print(){ cout << "(" << x << "," << y << ")" << endl; }
};
int main(){
int x1,x2,y1,y2;
cin >> x1 >> y1 >> x2 >> y2;
Complex_num c1(x1,y1), c2(x2,y2);
Complex_num c3 = c1.addition(c2);
c3.print();
return 0;
}

Public 1
Input: 1 3 5 6
Output: (6,9)

Public 2
Input: 2 -5 7 6
Output: (9,1)

Private
Input: 1 2 3 4
Output: (4,6)

11
Answer:
LINE-1: x( x), y( y)
LINE-2: x(c.x), y(c.y)
LINE-3: Complex num addition(Complex num c)
Explanation:
The parameterized constructor can be completed at LINE-1 as x( x), y( y). Similarly, the
copy constructor can be completed at LINE-2 as x(c.x), y(c.y). The function header at
LINE-3 can be completed as Complex num addition(Complex num c)

12
Question 2
Consider the following program.
• Fill in the blank at LINE-1 with the appropriate constructor statement.

• Fill in the blank at LINE-2 with the appropriate destructor statement so that the dynamic
memory allocated in the constructor can be properly deleted.
The program must satisfy the sample input and output. Marks: 3
#include<iostream>
using namespace std;
class CharArray{
char *arr;
int size;
public:
CharArray(int n) : ______________________{} //LINE-1
~CharArray(){ ________________; } //LINE-2
void EnterEle(){
for(int i=0;i<size;i++)
cin >> arr[i];
}
void FindMax(){
char max = -1;
for(int i=0;i<size;i++){
if(max < arr[i])
max = arr[i];
}
cout << "Max: " << max;
}
};
int main(){
int n;
cin >> n;
CharArray a(n);
a.EnterEle();
a.FindMax();
return 0;
}

Public 1
Input: 3 a b c
Output: c

Public 2
Input: 5 u a e o i
Output: u

Private
Input: 4 m a t y
Output: y

13
Answer:
LINE-1: arr(new char[n]), size(n)
LINE-2: delete[] arr
Explanation:
The parameterized constructor of the class should initialize the data members of the class.
Using the constructor, we need to allocate memory to the data member arr and initialize size.
So, LINE-1 needs to be filled as arr(new char[n]), size(n). The destructor should free
memory which is allocated dynamically to the data member arr. So, LINE-2 should be filled
as delete[] arr.

14
Question 3
Consider the following program.

• Fill in the blanks at LINE-1 to declare the data member z.

• Fill in the blanks at LINE-2 to complete the change() function header.

• Fill in the blanks at LINE-3 to complete the print() function header.

The program must satisfy the sample input and output. Marks: 3

#include<iostream>
using namespace std;
class Constant{
int x, y;
________________; //LINE-1
public:
Constant(int _x, int _y) : x(_x), y(_y){}
__________________________ { z = x * y; }; //LINE-2
______________________ { //LINE-3
cout << "x = " << x << ", y = " << y << ", z = " << z;
}
};
int main(){
int i, j;
cin >> i >> j;
const Constant m(i, j);
m.change();
m.print();
return 0;
}

Public 1
Input: 2 3
Output: x = 2, y = 3, z = 6

Public 2
Input: 5 7
Output: x = 5, y = 7, z = 35

Private
Input: 7 3
Output: x = 7, y = 3, z = 21

Answer:
LINE-1: mutable int z
LINE-2: void change() const
LINE-3: void print() const
Explanation:
Since m is defined as a constant object, and we need to modify the value of z, z has to be
defined as mutable member. Thus, the declaration of z can be as follows:

15
LINE-1: mutable int z Since the functions change() and print() called on a constant
object, they must be defined as constant functions as follows:
LINE-2: void change() const
LINE-3: void print() const

16
Programming in Modern C++: Assignment Week 4
Total Marks : 25

Partha Pratim Das


Department of Computer Science and Engineering
Indian Institute of Technology Kharagpur, Kharagpur – 721302
partha.p.das@gmail.com

February 7, 2024

Question 1
Consider the following program. [MSQ, Marks 2]

#include<iostream>
using namespace std;

class Test{
int x;
public:
Test(int _x) : x(_x) {}
________________________; //Line-1
};
class ReTest{
int d;
public:
ReTest(int x) : d(x) {}
void update(const Test& r){
cout << (d + r.x);
}
};

int main(){
Test t(10);
ReTest rt(20);
rt.update(t);
return 0;
}

Fill in the blank at LINE-1 so that the program will print 30.

a) friend class ReTest

b) class friend ReTest

c) static class ReTest

d) const class ReTest

1
Answer: a)
Explanation:
The ReTest class member function update() is accessing a private member of the class Test.
So, the class ReTest has to be a friend of class Test. So, the correct option is a).
Intentionally made as MSQ

2
Question 2
Consider the following code segment. [MCQ, Mark 2]

#include <iostream>
using namespace std;
int var = 0;
namespace Test {
int var = 2;
}
int main() {
________________________; // LINE-1
int var = 1;
{
cout << ::var << var << Test::var;
}
return 0;
}

Fill in the blank at LINE-1 so that the program will print 012.

a) using Test

b) namespace Test

c) using namespace Test

d) using namespace Test::var

Answer: c)
Explanation:
Syntax to include a namespace in the main function is defined as using namespace Test so
that the content can be used in the scope.

3
Question 3
Consider the following code segment. [MSQ, Marks 2]

#include<iostream>
using namespace std;
class Test{
______________ x; //LINE-1
public:
Test(double _x) : x(_x) {}
void set(double a) const{
x = a;
}
void print() const{
cout << x << endl;
}
};
int main(){
const Test t(3.14);
t.set(9.81);
t.print();
return 0;
}

Fill in the blank at LINE-1 so that the program will print 9.81.

a) mutable double

b) const double

c) static double

d) double mutable

Answer: a), d)
Explanation:
To change the value of the data member of a constant object, we need to declare the data
member as mutable. So, the syntax is mutable double or double mutable.

4
Question 4
Consider the following code segment. [MCQ, Marks 2]

#include<iostream>
using namespace std;
class Test{
static int s;
public:
void incr(int x){ s = s + x; }
void print(){ cout << s; }
};
int Test::s = 10;
int main(){
Test t1;
t1.incr(5);
Test t2;
t2.incr(10);
t1.print();
return 0;
}

What will be the output?

a) 10

b) 15

c) 20

d) 25

Answer: d)
Explanation:
The static data member Test::s is initialized during the program startup and is shared by
both objects t1 and t2 of the class Test. Hence, the data member is initialized as 10 during
the start of the main function. It is incremented two times when the incr() function is called
for both objects. Hence, the print() function will print 25.

5
Question 5
Consider the following code segment. [MCQ, Marks 2]

#include<iostream>
using namespace std;
class myClass{
static int a;
public:
void incr(){
a = a + 5;
}
static void display(){
cout << a;
}
};
int myClass::a = 0;
int main(){
myClass m;
m.incr();
__________________; //LINE-1
return 0;
}

Fill in the blank at LINE-1 so that the program will print 5.

a) display()

b) myClass::display()

c) myClass.display()

d) myClass->display()

Answer: b)
Explanation:
When a function is declared as static, it can be called using the class name. The syntax is
myClass::display().

6
Question 6
Consider the following code segment. [MCQ, Marks 2]

#include<iostream>
int main(){
char greet[] = "Hello";
cout << greet; //LINE-1
return 0;
}

Change the LINE-1 with the appropriate option so that the program will run successfully.

a) using cout << greet;

b) using std::cout << greet;

c) std::cout << greet;

d) std.cout << greet;

Answer: c)
Explanation:
cout is a predefined object in namespace std. In order to call cout function, we need to specify
that cout belongs to the std namespace. The correct syntax for the same is std::cout <<
greet; i.e. option c).

7
Question 7
Consider the following code segment. [MSQ, Marks 2]

#include<iostream>
using namespace std;
namespace n1{
int a = 1;
int b = 2;
}
namespace n2{
int c = 3;
int d = 4;
}

int main(){
using namespace n2;
cout << a << endl; //LINE-1
cout << n1::b << endl; //LINE-2
cout << n2::c << endl; //LINE-3
cout << d << endl; //LINE-4
return 0;
}

Which line/s will generate a compilation error?

a) LINE-1

b) LINE-2

c) LINE-3

d) LINE-4

Answer: a)
Explanation:
The variable a is declared within namespace n1 and is not accessible within the scope of the
main function because the namespace n1 is not included. Hence, LINE-1 will give an error.
The variable b is accessed using the namespace n1, which is perfectly fine. Hence, LINE-2 will
not give any error.
The variable c is accessed using the namespace n2, which is also fine and will not give any
error.
The variable a is declared in namespace n1, and it is included in the program. Hence, LINE-1
will not give any error.
This question is intentionally made as MSQ.

8
Question 8
Consider the following code segment. [MCQ, Marks 2]

#include <iostream>
using namespace std;
class classA{
int a=5;
public:
classA(int _a) : a(_a) {}
int get() { return a; }
};
class classB{
static classA c1;
public:
static int get(){
return c1.get();
}
};
int main(void){
cout << classB::get();
return 0;
}

What will be the output/error?

a) 0

b) 5

c) Compilation error: inaccessible object c1

d) Compilation error: undefined reference classB::c1

Answer: d)
Explanation:
The static variable c1 in classB needs to be initialized globally in order to use it. But there is
no initiation for c1 in the program. Thus, it gives a compilation error as Undefined reference
classB::c1.

9
Question 9
Consider the following code segment. [MCQ, Marks 2]

#include<iostream>
using namespace std;
class Test{
static int a;
public:
Test() { a++; }
static int get(){ return a; }
};
int Test::a = 0;
int main(){
cout << Test::get() << " ";
Test t[4];
cout << Test::get();
return 0;
}

What will be the output?

a) 0 3

b) 0 4

c) 1 3

d) 1 4

Answer: b)
Explanation:
The lifetime of a static class variable will be throughout the program. So, the static data
member of the class is initialized with 0 when the get() function is called. The first cout
statement prints 0. Next, the initializations of another four objects, increment the static
variable four times. Hence second cout statement prints 4.

10
Programming Questions

Question 1
Consider the program below.

• Fill in the blank at LINE-1 with appropriate keyword,

• Fill in the blank at LINE-2 with appropriate return type of the function,

• Fill in the blank at LINE-3 with the appropriate initialization statement of the static
variable obj.

The program must satisfy the given test cases. Marks: 3

#include<iostream>
using namespace std;
class myClass{
char c;
_______ myClass *obj; //LINE-1
myClass(char x) : c(x) { }
public:
________________ create(char x){ //LINE-2
if(!obj)
obj = new myClass(x);
return obj;
}
void show();
};
_____________________________ //LINE-3
void myClass::show(){
cout << c;
}
int main(){
int x, y;
myClass *s1, *s2;
cin >> x >> y;
s1 = myClass::create(x);
s2 = myClass::create(y);
s1->show();
s2->show();
return 0;
}

Public 1
Input: 97 98
Output: aa

Public 2
Input: 65 56
Output: AA

11
Private
Input: 101 110
Output: ee

Answer:
LINE-1: static
LINE-2: static myClass*
LINE-3: myClass *myClass::obj = 0;
Explanation:
The variable object should be declared as static so that the first instance of myClass is always
present throughout the program. The function create() returns the member object.
So, LINE-2 is filled as static myClass* . The static member of class should be initialized at
LINE-3 with myClass *myClass::object = 0.

12
Question 2
Consider the following program.

• Fill in the blank at LINE-1 with the appropriate statement such that the global function
can access private class members,

• Fill in the blank at LINE-2 with the appropriate statement such that the global function
can access private class members

The program must satisfy the sample input and output. Marks: 3

#include<iostream>
using namespace std;
class A{
int x;
public:
A(int _x) : x(_x){ cout << "Class A: "; }
______________________________ //LINE-1
};
class B{
int x;
public:
B(int _x) : x(_x){ cout << "Class B: "; }
_______________________________ //LINE-2
};
void print(int a, int b){
if(a == 1)
cout << A(b).x;
else
cout << B(b).x;
}
int main(){
int a, b;
cin >> a >> b;
print(a,b);
return 0;
}

Public 1
Input: 1 5
Output: Class A: 5

Public 2
Input: 2 3
Output: Class B: 3

Private
Input: 1 -1
Output: Class A: -1

13
Answer:
LINE-1: friend void print(int, int);
LINE-2: friend void print(int, int);
Explanation:
The global function print() is accessing private data members of both classes A and B. This
can be possible only when the function is friend of both classes. So, LINE-1 and LINE-2 will
be filled as friend void print(int, int);

14
Question 3
Consider the following program.
• Fill in the blanks at LINE-1, LINE-2, LINE-3 and LINE-4 with appropriate keywords
The program must satisfy the sample input and output. Marks: 3
#include<iostream>
using namespace std;
class Emp{
int id;
________ double basic; //LINE-1
________ double salary; //LINE-2
public:
Emp(int i, double b, double s=0) : id(i), basic(b), salary(s){ }
void setBasic(double b) _____{ //LINE-3
basic = b;
}
_______ double calculate(const Emp&); //LINE-4
};
double calculate(const Emp &e){
e.salary = e.basic + e.basic * 0.5;
return e.salary;
}
int main(){
int a;
double b,c;
cin >> a >> b >> c;
const Emp e(a,b);
cout << calculate(e) << " ";
e.setBasic(c);
cout << calculate(e);
return 0;
}

Public 1
Input: 1 1000 400
Output: 1500 600

Public 2
Input: 5 2000 200
Output: 3000 300

Private
Input: 2 5400 320
Output: 8100 480

Answer:
LINE-1: mutable
LINE-2: mutable
LINE-3: const

15
LINE-4: friend
Explanation:
In this program, we attempt to modify the values of the data members belonging to a constant
object. It can be done if the blanks at LINE-1 and LINE-2 are filled with keyword mutable.
The function calculate() is called using constant class object. It is done only when the blank
at LINE-3 is filled with const keyword. To access private data members from global function,
the function needs to be declared as friend at LINE-4.

16
Programming in Modern C++: Assignment Week 5
Total Marks : 25

Partha Pratim Das


Department of Computer Science and Engineering
Indian Institute of Technology Kharagpur, Kharagpur – 721302
partha.p.das@gmail.com

February 15, 2024

Question 1
Consider the following code segment. [MCQ, Marks 2]

#include <iostream>
using namespace std;
class Base {
protected:
double i;
public:
Base(double _i) : i(_i) {}
void calculate() { cout << i << endl; }
};
class Derived : public Base {
public:
Derived(double _i) : Base(_i) {}
void calculate(double pi) { cout << i * pi << endl; }
};
int main(){
Derived i1(6.75);
i1.calculate(); //LINE-1
return 0;
}

What will be the output/error?

a) 6.75

b) 0

c) 675

d) Compilation error: no matching function for call to ’Derived::calculate()’

Answer: d)
Explanation:
When we overload base class function in the derived class, the base class function will not be
available to call using derived class object. So, it will be compilation error at LINE-1.

1
Question 2
Consider the following code segment. [MCQ, Marks 2]

#include <iostream>
using namespace std;
class Base {
public:
void print() { cout << "C Programming" << endl; }
};
class Derived : public Base {
public:
void print() { cout << "C++ Programming" << endl; }
};
int main(){
Base *a1 = new Base();
Base *b1 = new Derived();
a1->print();
b1->print();
return 0;
}

What will be the output?

a) C Programming
C++ Programming

b) C++ Programming
C Programming

c) C Programming
C Programming

d) C++ Programming
C++ Programming

Answer: c)
Explanation:
Since print() is a non-virtual function, the binding of the function calls a1->print() and
b1->print() depend on the type of the pointers. In our case, both pointers are having C class
type. So, both pointer will call base class function Base::print(.).

2
Question 3
Consider the following code segment. [MCQ, Marks 2]

#include<iostream>
using namespace std;
class One{
public:
One() { cout<<"1 "; }
~One() { cout << "-1 "; }
};
class Two : public One {
public:
Two() { cout << "2 "; }
~Two() { cout << "-2 "; }
};
class Three : public Two{
Two b;
public:
Three() { cout << "3 "; }
~Three() { cout << "-3 "; }
};
int main(){
Three t1;
return 0;
}

What will be the output?

a) 1 2 3 -3 -2 -1

b) 1 2 1 2 3 -3 -2 -1 -2 -1

c) 1 3 -3 -1

d) 1 1 2 3 -3 -2 -1 -1

Answer: b)
Explanation:
When an object of class Three is being instantiated, the constructor of class Two is called, which
will print ”1 2” first. Then data member of class Three is created, which will again print ”1”
then print ”2”. Then at last ”3” is printed from constructor of class Three. After the end of
main() function, reverse of already printed sequence will be printed from the destructor of the
classes. So, the answer is (b).

3
Question 4
Consider the following code segment. [MSQ, Marks 2]

#include<iostream>
using namespace std;
class Father{
public:
void print() { cout << "Father" << endl; }
};
class Son : protected Father {
public:
Son() { ______________ } //LINE-1
};
int main(){
Son t1;
return 0;
}

Fill in the blank at LINE-1 so that the program will print Father.

a) Father::print();

b) Father.print();

c) (new Father)->print();

d) Father->print();

Answer: a), c)
Explanation:
It can be seen that the print() function needs to be called from class Son constructor in
order to print Father. So, it can be called using class name or temporary object. So, option
a) and c) are correct.

4
Question 5
Consider the following code segment. [MSQ, Marks 2]

#include<iostream>
using namespace std;
class Base {
int a;
public:
Base(int _a) : a(_a) { }
void f() { cout<< a; }
};
class Derived : public Base {
int b;
public:
Derived(int x, int y) : Base(x), b(y) { }
void f() { cout<< b; };
};
int main() {
Derived obj(1,2);
________________; //LINE-1
return 0;
}

Fill in the blank at LINE-1 so that the output is 1.

a) obj.Base->f()

b) obj.Base::f()

c) obj.Base.f()

d) Base::f()

Answer: b)
Explanation:
As the function f() need to be called from the base class Base, the appropriate syntax for
function call is obj.Base::f().
Intentionally made as MSQ

5
Question 6
Consider the following code segment. [MSQ, Marks 2]

#include <iostream>
using namespace std;
int x = 10;
class Class1{
protected:
int x;
public:
Class1() : x(20) {}
~Class1() {}
};
class Class2 : Class1{
protected:
int x;
public:
Class2() : x(30) {}
~Class2(){}
void print() { cout << _______________________________; } //LINE-1
};
int main(){
Class2 d;
d.print();
return 0;
}

Fill in the blank at LINE-1 so that the program will print 30 20 10.

a) Class2::x << " " << Class1::x << " " << x

b) Class2::x << " " << Class1::x << " " << ::x

c) x << " " << Class1::x << " " << ::x

d) ::x << " " << Class1::x << " " << x

Answer: b), c)
Explanation:
Since x = 30 is in the scope of class Class2 which is also the local scope for the function
print(), data can be accessed by writing Class2::x or just by x. Since x = 20 is in the scope
of class Class1, it can be accessed by writing Class1::x. Since x = 10 is in the global scope,
it can be accessed by writing ::x. So option b) and c) both are correct.

6
Question 7
Consider the following code segment. [MSQ, Marks 2]

#include<iostream>
using namespace std;
class Print{
int x;
public:
Print(int _x) : x(_x){ }
int fun(){ return x; }
};
class RePrint : public Print{
int y;
public:
RePrint(int _x, int _y) : ________________{} //LINE-1
void fun(){ cout << Print::fun() << y; }
};
int main(){
RePrint *b2 = new RePrint(2,3);
b2->fun();
return 0;
}

Fill in the blank at LINE-1 so that the program will print 23.

a) Print( x), y( y)

b) Print( y), y( x)

c) y( y), Print( x)

d) y( x), Print( y)

Answer: a), c)
Explanation:
It is noted that data member of class Print should be assigned with value 2 and data member
of class RePrint i.e. y should be assigned with value 3. Hence, option a) and c) are correct.
Note that, we need to call Base class constructor in order to assign value to its data member.

7
Question 8
Consider the following code segment. [MCQ, Marks 2]

#include<iostream>
using namespace std;
class A{
public:
int x;
A(int _x) : x(_x){}
};
class B : private A{
public:
int y;
B(int _x, int _y) : A(_x), y(_y){}
};
int main(){
A t1(1);
B t2(2,3);
cout << t1.x << " ";
cout << t2.x;
return 0;
}

What will be the output/error?

a) 1 2

b) 1 3

c) 1 1

d) Compilation error: int A::x is inaccessible

Answer: d)
Explanation:
The public class member of class A can be accessed from anywhere using the class object. So,
first cout function get complied successfully. In the second cout statement, we are trying
to access data member x using the B class object. Since the inheritance is private, the data
member x becomes private in the child class. Thus, it can not be accessed. It will give
compilation error.

8
Question 9
Consider the following code segment. [MSQ, Marks 2]

#include<iostream>
using namespace std;
class A{
public:
void printA(){ cout << "Class A"; }
};
class B : _____________ A{ //LINE-1
public:
void printB(){ cout << "Class B"; }
};
int main(){
B b;
b.printA();
return 0;
}

Fill in the blank at LINE-1 such that the program will run successfully without any error.

a) private

b) protected

c) public

d) friend

Answer: c)
Explanation:
The inherited members from the base class must appear as public in derived class so that
they can be accessed by outside functions. Only public inheritance makes sure that the public
members of the base class remain public in the derived class. Thus, c) is the correct option.
Intentionally made as MSQ

9
Programming Questions

Question 1
Complete the program with the following instructions.

• Fill in the blank at LINE-1 with appropriate inheritance statement,

• Fill in the blanks at LINE-2 appropriate initializer list,

The program must satisfy the given test cases. Marks: 3

#include<iostream>
using namespace std;
class B{
protected:
int b1;
public:
B(int b) : b1(b){}
};
class D{
protected:
int b2;
public:
D(int b) : b2(b){}
};
class DD : _____________________{ //LINE-1
int d;
public:
DD(int x) : ________________________{} //LINE-2
void show(){
cout << d << ", " << b1 << ", " << b2;
}
};
int main(){
int x;
cin >> x;
DD t1(x);
t1.show();
return 0;
}

Public 1
Input: 3
Output: 3, 6, 9

Public 2
Input: 10
Output: 10, 20, 30

10
Private 1
Input:5
Output: 5, 10, 15

Answer:
LINE-1: public B, public D
LINE-2: B(x*2), D(x*3), d(x)
Explanation:
The function show() of class DD is accessing protected member of both class B and class D.
This can be done when DD class is inherited from class B and D. So, LINE-1 will be filled as
public B, public D or protected inheritance in any order.
As per the test cases, the constructor at LINE-2 needs to be filled as B(x*2), D(x*3), d(x)
or in any order.

11
Question 2
Consider the following program with the following instructions.

• Fill in the blank at LINE-1 with appropriate keyword.

• Fill in the blanks at LINE-2 and LINE-3 to complete the constructor statements.

The program must satisfy the sample input and output. Marks: 3

#include<iostream>
using namespace std;
class Student{
string n;
string s;
int m;
protected:
Student(string _n, string _s, int _m) : n(_n), s(_s), m(_m) {}
public:
_______ void studDetails(const Student&); //LINE-1
};
class Bengali : public Student{
public:
Bengali(string n, int m) : ___________________{} //LINE-2
};
class English : public Student{
public:
English(string n, int m) : __________________{} //LINE-3
};
void studDetails(const Student &st){
cout << st.n << " --> (" << st.s << " - " << st.m << ")";
}
int main(){
string s;
int m, n;
Student *st;
cin >> m >> s >> n;
if (m==1)
st = new Bengali(s, n);
else if (m==2)
st = new English(s, n);
studDetails(*st);
return 0;
}

Public 1
Input: 1 50 65
Output: 50 --> (Bengali - 65)

Public 2
Input: 2 30 43
Output: 30 --> (English - 43)

12
Private
Input: 1 80 55
Output: 80 --> (Bengali - 55)

Answer:
LINE-1: friend
LINE-2: Student(n, "Bengali", m)
LINE-3: Student(n, "English", m)
Explanation:
The global function studDetails() needs to access private members of class Student. So, it
should be a friend function of class Student. The blank at LINE-1 must be filled with friend.
From LINE-2, constructor of class Student needs to be called with sub value as ”Bengali”. It
can be done as Student(n, "Bengali", m).
In the similar way, LINE-3 will be filled as Student(n, "English", m).

13
Question 3
Consider the following program. Fill in the blanks as per the instructions given below:

• Fill in the blank at LINE-1 with appropriate return statement,

• Fill in the blank at LINE-2 with appropriate return statement,

The program must satisfy the given test cases. Marks: 3

#include<iostream>
#define PI 3.14
using namespace std;
class Area{
public:
double getVal(int r){ return (4*PI*r*r); }
};
class Volume{
public:
double getVal(int r){ return (4*PI*r*r*r/3); }
};
class Sphere : public Area, public Volume{
int r;
public:
Sphere(int _r) : r(_r){ }
double getArea(){ return _______________; } //LINE-1
double getPerimeter(){ return ____________________; } //LINE-2
};
int main(){
int a;
cin >> a;
Sphere s(a);
cout << s.getArea() << ", " << s.getPerimeter();
return 0;
}

Public 1
Input: 2
Output: 50.24 33.4933

Public 2
Input: 4
Output: 200.96 267.947

Private
Input: 3
Output: 113.04 113.04

Answer:
LINE-1: Area::getVal(r)
LINE-2: Volume::getVal(r)
Explanation:

14
The class Circle must inherit from both Area and Volume classes.
The function getVal() is defined in both Area and Volume classes. To resolve the ambi-
guity, we need to use Area::getVal(r) at LINE-1 to call getVal() from class Area and
Volume::getVal(r) at LINE-3 to call getVal() from class Volume.

15
Programming in Modern C++: Assignment Week 6
Total Marks : 25

Partha Pratim Das


Department of Computer Science and Engineering
Indian Institute of Technology Kharagpur, Kharagpur – 721302
partha.p.das@gmail.com

February 22, 2024

Question 1
Consider the following code segment. [MCQ, Marks 2]

#include<iostream>
using namespace std;
class ClassA{
public:
void fun1() { cout << "A1" ; }
virtual void fun2() { cout << "A2" ; }
};
class ClassB : public ClassA{
public:
virtual void fun1() { cout << "B1" ; }
void fun2() { cout << "B2" ; }
};
int main(){
ClassA *t = new ClassB();
t->fun1();
t->fun2();
return 0;
}

What will be the output?

a) A1B1

b) A1B2

c) A2B1

d) A2B2

Answer: b)
Explanation:
As fun1() is a non-virtual function at the base class, for the t->fun1() function call static
binding is done. So, the function of pointer type will be called.
As fun2() is a virtual function, for the t->fun2() function call dynamic binding is done. So,
the function of object type will be called.

1
Question 2
Consider the following code segment. [MCQ, Marks 2]

#include<iostream>
using namespace std;
class ClassA{
public:
virtual void fun() = 0;
};
class ClassB{
public:
virtual void fun(){ }
};
class ClassC{
int x;
public:
void fun(){ }
};
int main(){
cout << sizeof(ClassA) << " " << sizeof(ClassB) << " " << sizeof(ClassC);
return 0;
}

What will be the output?

a) 8 8 1

b) 8 8 4

c) 1 8 4

d) 0 1 4

Answer: b)
Explanation:
Class ClassA and ClassB have virtual functions hence, each of them has a pointer to VFT
which is of 8 bytes. Hence, sizeof(ClassA) and sizeof(ClassB) is 8. Class ClassC has a
data member of int type. Hence, sizeof(ClassC) = 4. Option b) is correct.

2
Question 3
Consider the following code segment. [MCQ, Marks 2]

#include<iostream>
using namespace std;
class A{
public:
A() { cout<<"A "; }
~A() { cout<<"~A "; }
};
class B : public A{
public:
B() { cout<<"B "; }
virtual ~B() { cout<<"~B "; }
};
class C : public B{
public:
C() { cout<<"C "; }
virtual ~C() { cout<<"~C "; }
};
int main(){
A *t1 = new C;
delete t1;
return 0;
}

What will be the output?

a) A B C ∼C ∼B ∼A

b) A B C ∼C ∼B

c) A B C ∼B ∼A

d) A B C ∼A

Answer: d)
Explanation:
When the object of class C is created, it calls constructor of class C which in turn calls con-
structor of class B and A respectively. So, it will print A B C.
Whenever, the object is deleted, it calls destructor of class A first. The destructor of class A is
not virtual, so it will not call child class destructor. So, final result will be A B C ∼A.

3
Question 4
Consider the following code segment. [MSQ, Marks 2]

#include <iostream>
using namespace std;
class myClass {
public:
virtual void test() = 0; //LINE-1
};
void myClass::test() {
cout << "Pure virtual function";
}
int main() {
myClass m; // LINE-2
myClass *p = new myClass(); // LINE-3
myClass.test(); // LINE-4
return 0;
}

Which line/s will NOT give you error?

a) LINE-1

b) LINE-2

c) LINE-3

d) LINE-4

Answer: a)
Explanation:
Any abstract base class cannot be instantiated and hence will give an error at LINE-2. Also, we
cannot create abstract class object using new operator and hence will give an error at LINE-3.
The test() function is implemented in class myClass. Hence, the class is not pure virtual.
So, LINE-4 will also give error. So, the correct option is a).
Intentionally made as MSQ

4
Question 5
Consider the following code segment. [MSQ, Marks 2]

#include<iostream>
using namespace std;
class Base{
public:
virtual void fun() { cout << "Base"; }
};
class Derived : public Base{
public:
void fun(double i) { cout << "Derived"; }
};
int main(){
Derived t1;
Base *t2 = new Derived();
t1.fun(); //LINE-1
t1.fun(3.14); //LINE-2
t2->fun(9.8); //LINE-3
t2->fun(); //LINE-4
return 0;
}

Which line/s will give you error?

a) LINE-1

b) LINE-2

c) LINE-3

d) LINE-4

Answer: a), c)
Explanation:
The function fun() of class Base is overloaded in class Derived. So, base class function become
hidden for derived class. So, LINE-1 will give error. On the other hand, class Base doesn’t
have fun(double) in its definition. So, LINE-3 will give an error.

5
Question 6
Consider the following code segment. [MSQ, Marks 2]

#include<iostream>
using namespace std;
class Class1{
public:
virtual void fun(){ cout << "Class1::fun() "; }
};
class Class2 : public Class1{
public:
void fun(){ cout << "Class2::fun() "; }
};
class Class3 : public Class2{
public:
void fun(){ cout << "Class3::fun() "; }
};
int main(){
Class1 *cb = ____________; //LINE-1
cb->fun();
return 0;
}

Fill in the blank at LINE-1 such that the program will print Class2::fun().

a) new Class1

b) new Class2

c) new Class3

d) It cannot be printed

Answer: b)
Explanation:
If a function is declared as virtual, the function call depends on the type of object the pointer
points to, not on the type of the pointer. Hence, to call function fun() from Class2 class,
LINE-1 need to be filled as new Class2.

6
Question 7
Consider the following code segment. [MCQ, Marks 2]

#include<iostream>
using namespace std;
class ClassA{
int b;
public:
ClassA(int i) : b(i) {}
virtual void f(ClassA *t) { cout << t->b << endl; }
};
class ClassB : public ClassA{
int d;
public:
ClassB(int i=0, int j=0) : ClassA(i), d(j) { }
void f(ClassB *t) { cout << t->d << endl; }
};
int main(){
ClassA *t1 = new ClassB(1,2);
t1->f(new ClassB); //Line-1
return 0;
}

What will be the output?

a) 0

b) 1

c) 2

d) Garbage values

Answer: a)
Explanation:
The function call at LINE-1 invokes derived class function with a temporary object as param-
eter. The temporary object of class ClassB has data members with value 0 as constructor
initializes both the data members with default value 0. Hence, the program will print 0.

7
Question 8
Consider the following code segment. [MCQ, Marks 2]

#include<iostream>
using namespace std;
class classA{
public:
virtual void f(){ cout << "1 "; }
};
class classB : public classA{
public:
void f(){ cout << "2 "; }
};
class classC : public classB{
public:
void f(){ cout << "3 "; }
};
int main(){
classC *cb = new classC;
_____________________; //LINE-1
return 0;
}

Fill in the blank at LINE-1 so that the program will print 1.

a) cb->f()

b) classA::cb->f()

c) cb->classA::f()

d) classA::f()

Answer: c)
Explanation:
As cb is a pointer to object of class classC, we can call f() from class classA as cb->classA::f()
such that it will print 1.

8
Question 9
Identify the abstract class/es from the following code snippet. [MCQ, Marks 2]

class Flower {
public:
virtual void desc() = 0 { cout << "Flower"; }
};

class FlowerWSmell : public Flower {


void desc() { cout << "Flower with smell"; }
};

class FlowerWOSmell : public Flower {};

class Tuberose : public FlowerWSmell {


public:
void desc() { cout << "Tuberose Flower"; }
};

class Jasmine : public FlowerWSmell {


public:
void desc() { cout << "Jasmine Flower"; }
};

class Sunflower : public FlowerWOSmell {


public:
void desc() { cout << "Sunflower flower"; }
};

class Dahlia : public FlowerWOSmell {};

a) Flower, FlowerWSmell, FlowerWOSmell

b) Flower, FlowerWOSmell, Dahlia

c) Flower, FlowerWSmell, FlowerWOSmell, Sunflower

d) Flower

Answer: b)
Explanation:
An abstract base class contains at least one pure virtual function. Moreover a class derived
from an abstract base class will also be abstract unless you override each pure virtual function
in the derived class with non-pure ones. So option b) is the correct answer.

9
Programming Questions

Question 1
Complete the program with the following instructions.
• Fill in the blank at LINE-1 with appropriate keyword,
• Fill in the blanks at LINE-2 to declare fun() as a pure virtual function,
• fill in the blank at LINE-3 with approriate object instantiation,
The program must satisfy the given test cases. Marks: 3
#include<iostream>
using namespace std;
class Base{
protected:
int s;
public:
Base(int i=0) : s(i){}
_______ ~Base(){ } //LINE-1
______________________ //LINE-2
};
class Derived : public Base{
int x;
public:
Derived(int i, int j) : Base(i), x(j) {}
~Derived();
int fun(){
return s*x;
}
};
class Wrapper{
public:
void fun(int a, int b){
Base *t = _______________; //LINE-3
int i = t->fun();
cout << i << " ";
delete t;
}
};
Derived::~Derived(){ cout << int(s/x) << " "; }
int main(){
int i, j;
cin >> i >> j;
Wrapper w;
w.fun(i,j);
return 0;
}

Public 1
Input: 5 2
Output: 10 2

10
Public 2
Input: 8 4
Output: 32 2

Private 1
Input: 9 5
Output: 45 1

Answer:
LINE-1: virtual
LINE-2: virtual int fun() = 0;
LINE-3: new Derived(a, b)
Explanation:
The destructor of Base class needs to be declared as virtual in order to call Derived class
destructor at the time of deletion. The function fun can be declared as pure virtual function
at LINE-2 as virtual int fun() = 0;. We can’t instantiate abstract class. So, LINE-3 can
be filled as new Derived(a, b).

11
Question 2
Consider the following program with the following instructions.
• Fill in the blank at LINE-1 and LINE-2 with appropriate return statements
The program must satisfy the sample input and output. Marks: 3
#include <iostream>
using namespace std;
const double ir = 7;
const double bonus = 4;
class FD{
protected:
double principal;
public:
FD(double _p = 0.0) : principal(_p){}
double getInterest(){ return principal * ir / 100; }
double getExtraAmt(){ return principal * bonus / 100 ; }
virtual double getMaturity() = 0;
};
class Customer : public FD{
public:
Customer(double _amt) : FD(_amt){}
double getMaturity();
};
class Employee : public FD{
public:
Employee(double _amt) : FD(_amt){}
double getMaturity();
};
double Customer::getMaturity(){
return _____________________; //LINE-1
}
double Employee::getMaturity(){
return ______________________________; //LINE-2
}
int main(){
double d;
cin >> d;
FD *ep[2] = {new Customer(d), new Employee(d)};
cout << ep[0]->getMaturity() << " ";
cout << ep[1]->getMaturity();
return 0;
}

Public 1
Input: 100 100
Output: 107 111

Public 2
Input: 1000 5000
Output: 1070 1110

12
Private
Input: 10 20
Output: 10.7 11.1

Answer:
LINE-1: FD::getInterest() + principal
LINE-2: FD::getInterest() + FD::getExtraAmt() + principal
Explanation:
To satisfy the test cases, we must call the functions FD::getInterest() and FD::getExtraAmt().
The blank at LINE-1 must be filled by:
FD::getInterest() + principal
and the blank at LINE-2 must be filled by:
FD::getInterest() + principal

13
Question 3
Consider the following program. Fill in the blanks as per the instructions given below:

• Fill in the blank at LINE-1 with an appropriate destructor declaration.

• Fill in the blank at LINE-2 with an appropriate constructor statement.

such that it will satisfy the given test cases. Marks: 3

#include<iostream>
using namespace std;
class A{
public:
A(){ cout << "11 "; }
A(int n){ cout << n + 2 << " "; }
______________; //LINE-1
};

class B : public A{
public:
B(int n) : ________ //LINE-2
{
cout << n + 5 << " ";
}
B(){ cout << "21 "; }
virtual ~B(){ cout << "22 "; }
};
A::~A(){ cout << "12 "; }
int main(){
int i;
cin >> i;
A *pt = new B(i);
delete pt;
return 0;
}

Public 1
Input: 4
Output: 6 9 22 12

Public 2
Input: 5
Output: 7 10 22 12

Private
Input: 8
Output: 10 13 22 12

Answer:
LINE-1: virtual ∼A()
LINE-2: A(n)

14
Explanation:
At LINE-1, the destructor need to be defined as virtual destructor, so that if the derived class
object gets deleted it will be called automatically. Hence, LINE-1 has to be filled with virtual
∼A();
The initialization-list required at LINE-2 is A(n).

15
Programming in Modern C++: Assignment Week 7
Total Marks : 25

Partha Pratim Das


Department of Computer Science and Engineering
Indian Institute of Technology Kharagpur, Kharagpur – 721302
partha.p.das@gmail.com

February 28, 2024

Question 1
Consider the following code segment. [MSQ, Marks 2]
#include <iostream>
using namespace std;
class student {
int roll ;
int marks;
public:
student(int _r, int _m) : roll(_r), marks(_m) {}
void update(int m) const{
(____________________)->marks = m; //LINE-1
}
void showInfo() const {
cout << roll << " : " << marks;
}
};
int main(void) {
const student s(3000, 56);
s.update(50);
s.showInfo();
return 0;
}
Fill in the blank at LINE-1 such that the program will print 3000 : 50.
a) const cast <student*> (this)

b) static cast <student*> (this)

c) dynamic cast <student*> (this)

d) (student*)(this)
Answer: a), d)
Explanation:
The statement const student s(3000, 56); defines s as a constant object. To modify its
data members, the constant-ness of the object needs to be removed. This can be done either
by const cast (in option a) or casting constant this pointer to student* type (in option d).

1
Question 2
Consider the following code segment. [MSQ, Marks 2]

#include <iostream>
using namespace std;
int main() {
char c = ’C’;
int d = 10;
char *cp = &c;
int *pd;
c = static_cast<char>(d); // LINE-1
d = static_cast<int>(c); // LINE-2
pd = static_cast<int*>(cp); // LINE-3
c = static_cast<char>(&c); // LINE-4
return 0;
}

Which line/s will give you an error?

a) LINE-1

b) LINE-2

c) LINE-3

d) LINE-4

Answer: c), d)
Explanation:
static cast cannot cast between two different pointer types. In LINE-3, int* is assigned to
char*. Hence it is an error.
Using static cast, it is not possible to change a pointer type to a value type. In LINE-4, char*
is assigned to char which is not possible using static cast.

2
Question 3
Consider the following code segment. [MSQ, Marks 2]

class Test1 { };
class Test2 : public Test1 { };
int main(){
Test1* t1 = new Test1;
Test2* t2 = new Test2;
t2 = __________________(t1);
return 0;
}

Fill in the blank at LINE-1 such that the program will be compiled successfully.

a) static cast<Test2*>

b) dynamic cast<Test2*>

c) reinterpret cast<Test2*>

d) const cast<Test2*>

Answer: a), c)
Explanation:
On each option, there is an attempt to cast from Test1* to Test2*. As we know, reinterpret cast
can be used to convert a pointer to an object of one type to a pointer to another object of
an unrelated type. Moreover, static cast is used to convert a base class object to a derived
class object. Hence option a) and c) are correct.

3
Question 4
Consider the following code segment. [MCQ, Marks 2]

class Test1 { };
class Test2 { };
Test1* t1 = new Test1;
Test2* t2 = new Test2;

Which of the following type-casting is permissible?

a) t2 = static cast<Test2*>(t1);

b) t2 = dynamic cast<Test2*>(t1);

c) t2 = reinterpret cast<Test2*>(t1);

d) t2 = const cast<Test2*>(t1);

Answer: c)
Explanation:
On each option, there is an attempt to cast from Test1* to Test2*, and these two classes are
unrelated. As we know, only reinterpret cast can be used to convert a pointer to an object
of one type to a pointer to another object of an unrelated type. Hence only option c) is correct.

4
Question 5
Consider the following code segment. [MCQ, Marks 2]

#include <iostream>
#include <typeinfo>
using namespace std;
class B { public: ~B(){}};
class D: public B {};
int main() {
B b;
D d;
D *dp = &d;
B *bp = dp;
D *dpp = (D*)dp;
cout << (typeid(bp).name() == typeid(dpp).name());
cout << (typeid(*bp).name() == typeid(*dpp).name());
cout << (typeid(dp).name() == typeid(dpp).name());
cout << (typeid(*dp).name() == typeid(*dpp).name());
return 0;
}

What will be the output?

a) 0101

b) 0111

c) 0110

d) 0011

Answer: d)
Explanation:
Type of bp is B* and type of dpp is D*. Thus, output is 0.
*bp and *dpp point to the same object d, and it is a static binding situation. Thus, both are
of type D and output is 0.
Type of dp and dpp is D*. Thus, output is 1.
*dp and *dpp point to the same object d, and it is a dynamic binding situation. Thus, both
are of type D and output is 1.

5
Question 6
Consider the following code segment. [MCQ, Marks 2]

#include <iostream>
using namespace std;
class A{ public: virtual ~A(){} };
class B : public A{};
class C : public A{};
int main(){
A objA;
B objB;
A* pA = dynamic_cast<A*>(&objB); //LINE-1
pA == NULL ? cout << "A" : cout << "B";
B* pB = dynamic_cast<B*>(pA); //LINE-2
pB == NULL ? cout << "A" : cout << "B";
C* pC = dynamic_cast<C*>(new A); //LINE-3
pC == NULL ? cout << "A" : cout << "B";
pC = dynamic_cast<C*>(&objB); //LINE-4
pC == NULL ? cout << "A" : cout << "B";
return 0;
}

What will be the output?

a) ABAB

b) BABA

c) BBAA

d) BABB

Answer: c)
Explanation:
The type-casting at LINE-1 is valid as it is an upper-casting. Hence, prints B.
At LINE-2, though it is a down-casting, it is allowed as the pointer pB points to the same type
of object (which of type B). Hence, prints B.
At LINE-3, the down-casting is invalid as the pointer pC points to parent type of object (which
is of type A). Hence prints A.
At LINE-4, the casting is also invalid as the pointer pC points to an object (which is of type
B) that is neither of its base type or derived type and hence prints A.

6
Question 7
Consider the following code segment. [MSQ, Marks 2]

#include<iostream>
using namespace std;
class A{
public:
virtual void F() {}
void G() {}
};
class B : public A{
public:
virtual void G() {}
void H() {}
virtual void I();
};
class C : public B{
public:
void G() {}
virtual void H() {}
};
class D : public C{
public:
void H() {}
};

What will be the VFT for the class C?

a) A::F(A* const)
C::G(C* const)
C::H(C* const)
B::I(B* const)

b) A::F(A* const)
B::G(B* const)
C::H(C* const)
B::I(B* const)

c) A::F(A* const)
B::G(B* const)
B::H(B* const)
C::I(C* const)

d) A::F(A* const)
B::G(C* const)
C::H(C* const)
C::I(C* const)

Answer: a)
Explanation:

7
All four functions are virtual in the class C. So, there will be four entries in virtual function
table.
Now function F() is not overridden in class B and C. So, the entry for function F() in the
virtual function table of class C will be A::F(A* const).
The function G() is virtual from class B and is overridden in class C. So, the entry for function
G() in VFT of class C will be C::G(C* const).
The function H() is declared as virtual in class C. So, the entry for function H() in VFT of
class C will be C::H(C* const).
Also, I() will be in the VFT as B::I(B* const)

8
Question 8
Consider the following code segment. [MSQ, Marks 2]

#include <iostream>
using namespace std;
int main() {
const int i = 100;
const int *pi = &i;
int *qi = __________________(pi); //LINE-1
*qi = 200;
cout << *qi;
return 0;
}

Fill in the blank at LINE-1 so that the program will print ”200”.

a) const cast<int*>

b) static cast<int*>

c) dynamic cast<int*>

d) (int*)

Answer: a), d)
Explanation:
At LINE-1, pi of type const int* needs to be casted to int*. It can be accomplished by
const cast<int*>(pi) or (int*).

9
Question 9
Consider the code segment given below. [MCQ, Marks 2]

class Person {
public:
virtual void sleep() = 0;
virtual void work() {};
};
class Man: public Person {
public:
void sleep() {};
virtual void work() {};
};
class Woman: public Person{
public:
void sleep() {}
void work(){}
};
class Child{
public:
void play() {};
void cry() {};
};

How many virtual function table (VFT) will be created?

a) 1

b) 2

c) 3

d) 4

Answer: c)
Explanation:
All the classes Person, Man and Woman consist of some virtual functions. Thus, 3 virtual
function tables would be created.
The class Child does not have any virtual function. So no virtual function tables would be
created.

10
Programming Questions

Question 1
Complete the program with the following instructions.
• Fill in the blank at LINE-1 to complete operator overloading for assignment operator.
• Fill in the blanks at LINE-2 and LINE-3 to complete the type casting statements.
The program must satisfy the given test cases. Marks: 3
#include<iostream>
using namespace std;
class Test1{
int a = 10;
public:
void show(){
cout << a ;
}
_________________{ //LINE-1
a = a + x;
}
};
class Test2 : public Test1{
int b = 20;
public:
void show(){
cout << b << " ";
}
};
void fun(const Test2 &t, int x){
Test2 &u = _________________(t); //LINE-2
u.show();
Test1 &v = ___________________(u); //LINE-3
v = x;
v.show();
}
int main(){
Test2 t1;
int x;
cin >> x;
fun(t1, x);
return 0;
}

Public 1
Input: 4
Output: 20 14

Public 2
Input: 9
Output: 20 19

11
Private 1
Input: 15
Output: 20 25

Answer:
LINE-1: void operator=(int x)
LINE-2: const cast<Test2&>
LINE-3: reinterpret cast<Test1&>
Explanation:
As per the function fun(), we need to overload the operator equal to for the class Test1 at
LINE-1 so that the assignment v = x will be valid. It can be done as void operator=(int
x).
To call a non-constant function show() using a const object reference u, we need to cast the
reference to a non-const reference. So, LINE-2 will be filled as const cast<Test2&>.
Casting between two unrelated classes at LINE-3 can be done as reinterpret cast<Test1&>.

12
Question 2
Consider the following program with the following instructions.

• Fill in the blank at LINE-1 to complete constructor definition.

• Fill in the blank at LINE-2 to complete assignment operator overload function signature.

• Fill in the blank at LINE-3 to complete integer cast operator overload function signature.

The program must satisfy the sample input and output. Marks: 3

#include<iostream>
using namespace std;
class StringClass{
int *arr;
int n;
public:
StringClass(int k) : _________________________{} //LINE-1
_______________________{ //LINE-2
return arr[--n];
}
______________________________________(int &k){ //LINE-3
int t;
for(int j = 0; j < k; j++){
cin >> t;
this->arr[j] = t;
}
return *this;
}
};
int main(){
int k;
cin >> k;
StringClass str(k);
str = k;
for(int i = 0; i < k; i++)
cout << static_cast<int>(str) << " ";
return 0;
}

Public 1
Input: 3
1 3 5
Output: 5 3 1

Public 2
Input: 4
5 6 4 8
Output: 8 4 6 5

13
Private
Input: 6
1 2 3 4 5 7
Output: 7 5 4 3 2 1

Answer:
LINE-1: n(k), arr(new int(n))
LINE-2: operator int()
LINE-3: StringClass operator=
Explanation:
The initialization of the data-members at LINE-1 can be done as:
n(k), arr(new int(k))
At LINE-2, we overload type-casting operator for the statement static cast〈int〉(str) as:
operator int()
At LINE-3, we overload operator= for the statement str = k; as:
StringClass operator=(int& k)

14
Question 3
Consider the following program. Fill in the blanks as per the instructions given below:

• at LINE-1, LINE-2, LINE-3 and LINE-4 with appropriate inheritance statements

such that it will satisfy the given test cases. Marks: 3

#include<iostream>
using namespace std;
class B {
public:
B(int i) { cout << 50 * i << " "; }
B() { cout << 1 << " "; }
};
class D1 : ________________ { //LINE-1
public:
D1(int i);
};
class D2 : _________________ { //LINE-2
public:
D2(int i);
};
class D3 : __________________ { //LINE-3
public:
D3(int i);
};
class DD : ______________________________ { //LINE-4
public:
DD (int i) : D1(i), D2(i), D3(i) {
cout << 2 * i << " ";
}
};
D1::D1(int i) : B(i) {
cout << 5 * i << " ";
}
D2::D2(int i) : B(i) {
cout << 4 * i << " ";
}
D3::D3(int i) : B(i) {
cout << 3 * i << " ";
}
int main() {
int i = 0;
cin >> i;
DD dd(i);
return i;
}

Public 1
Input: 2
Output: 1 8 10 6 4

15
Public 2
Input: 3
Output: 1 12 15 9 6

Private
Input: 5
Output: 1 20 25 15 10

Answer:
LINE-1: virtual public B
LINE-2: virtual public B
LINE-3: virtual public B
LINE-4: public D2, public D1, public D3
Explanation:
If we observe the test-cases, the parametrized constructor is never called for the base class,
which implies all the derived classes have virtually inherited the base class. Therefore, the
blanks at LINE-1, LINE-2 and LINE-3 all have to be filled with: virtual public B The
order for invocation of the base class constructors depends on the order of inheritance. Again
from the test-cases it can be observed the sequence of inheritance at LINE-4 must be: public
D2, public D1, public D3

16
Programming in Modern C++: Assignment Week 8
Total Marks : 25

Partha Pratim Das


Department of Computer Science and Engineering
Indian Institute of Technology Kharagpur, Kharagpur – 721302
partha.p.das@gmail.com

March 7, 2024

Question 1
Consider the following code segment. [MCQ, Marks 2]

#include<iostream>

void f(){
try{
throw 10.8;
}
catch(int& e){ throw e; }
}

int main(){
try{
f();
}
catch(...){ std::cout << "all"; } //LINE-1
catch(int& e){ std::cout << "int"; }
catch(double& e){ std::cout << "double"; }
return 0;
}

What will be the output/error?

a) all

b) int

c) double

d) Compiler error LINE-1: ’...’ handler must be the last handler for its try block

Answer: d)
Explanation:
catch(...) { ... } must be the last handler for its try block. Thus, it generates an error
at LINE-1.

1
Question 2
Consider the program given below. [MCQ, Marks 2]

#include<iostream>

void f(int i){


try{
if(i < 0)
throw "negetive";
else if(i > 0)
throw i * 1.00;
else
throw 0;
}
catch(int ){ std::cout << "int "; } //LINE-1
catch(float ){ std::cout << "float "; } //LINE-2
catch(const char* ){ std::cout << "char * "; } //LINE-3
}
int main(){
for(int i = 2; i >= 0; ) {
try{
f(--i);
}catch(...) { std::cout << "all "; } //LINE-4
}
}

What will be the output?

a) float int char *

b) int float

c) all int char *

d) all

Answer: c)
Explanation:
For call f(1); it executes statement throw i * 1.00;, which throws double type exception.
double type exception will not be handled within the function f. So the exception will be
handled in main and ”all” will be printed.
For call f(0); it executes statement throw 0;, which throws int type exception. int type
exception will be handled in the f function and it prints int .
For call f(-1); it executes statement throw "negetive";, which throws char * type excep-
tion. char * type exception will be handled in the f function and it prints char *.

2
Question 3
Consider the program given below. [MCQ, Marks 2]

#include<iostream>

namespace DBErrors{
class SQLException {};
class KeyException : public SQLException {};
class PrimaryKeyException : public KeyException{};
class ForeignKeyException : public KeyException{};

class DBCon{
public:
static void print_err(int eno = 0){
try{
if(eno == 0)
throw PrimaryKeyException();
else if(eno < 0)
throw ForeignKeyException();
else if (eno > 0 && eno < 10)
throw KeyException();
else
throw SQLException();
}
catch(KeyException&) { std::cout << "DBErrors::KeyException"; }
}
};
}

int main(){
try{
_____________________________; //LINE-1
}
catch(DBErrors::PrimaryKeyException&) {
std::cout << "DBErrors::PrimaryKeyException&";
}
catch(DBErrors::ForeignKeyException&) {
std::cout << "DBErrors::ForeignKeyException";
}
catch(DBErrors::SQLException) {
std::cout << "DBErrors::SQLException";
}
return 0;
}

Identify the option/s to fill in the blank at LINE-1 such that output IS NOT
DBErrors::KeyException.

a) DBErrors::DBCon::print err(-10)

b) DBErrors::DBCon::print err(0)

3
c) DBErrors::DBCon::print err(7)

d) DBErrors::DBCon::print err(20)

Answer: d)
Explanation:
For option d), it throws exception SQLException(), which is not handled by the catch block
within the function print err(). It would be forwarded to main function, where it will handed
by printing DBErrors::SQLException.
For all other options, the exception thrown would be handled within the function print err()
since KeyException is the base class of PrimaryKeyException and ForeignKeyException,
and it will print DBErrors::KeyException.

4
Question 4
Consider the program given below. [MCQ, Marks 2]

#include<iostream>

namespace DBErrors{
class SQLException {
public:
virtual const char* what() const throw() {
return "SQLException";
}
};
class KeyException : public SQLException {
public:
virtual const char* what() const throw() {
return "KeyException";
}
};
class PrimaryKeyException : public KeyException{
public:
virtual const char* what() const throw() {
return "PrimaryKeyException";
}
};
class ForeignKeyException : public KeyException{
public:
virtual const char* what() const throw() {
return "ForeignKeyException";
}
};
}

int main(){
try{
throw DBErrors::PrimaryKeyException(); //LINE-1
}
catch(DBErrors::SQLException& e) {
std::cout << e.what();
}
catch(DBErrors::KeyException& e) {
std::cout << e.what();
}
catch(DBErrors::PrimaryKeyException& e) {
std::cout << e.what();
}
catch(DBErrors::ForeignKeyException& e) {
std::cout << e.what();
}
return 0;
}

5
What will be the output?

a) SQLException

b) KeyException

c) PrimaryKeyException

d) ForeignKeyException

Answer: c)
Explanation:
The exception thrown at LINE-1 would be caught by catch(DBErrors::SQLException& e)
block, since the thrown exception DBErrors::PrimaryKeyException is subclass of
DBErrors::SQLException. However, the reference e would be referring to the DBErrors::SQLException.
Therefore, what() would be invoked from DBErrors::SQLException.

6
Question 5
Consider the code segment given below. [MCQ, Marks 2]

#include<iostream>

________________________________________ //LINE-1
class TempTest{
public:
TempTest(T1 a, T2 b){
a_ = a;
b_ = b;
}
void test(){
std::cout << "a = " << a_ << ", b = " << b_ << std::endl;
}
private:
T1 a_;
T2 b_;
};

int main(){
TempTest<int> tt1(97, 65);
TempTest<> tt2(97, 65);
tt1.test();
tt2.test();
return 0;
}

Fill in the blank at LINE-1 such that the output of the program is:

a = 97, b = A
a = a, b = A

a) template<typename T1, typename T2>

b) template<typename T1 = char, typename T2 = char>

c) template<typename T1=int, typename T2>

d) template<typename T1=int, typename T2=char>

Answer: b)
Explanation:
From the output, it can be concluded that the default type of T1 and T2 are char. Thus,
option b) is correct.

7
Question 6
Consider the code segment given below. [MSQ, Marks 2]

#include<iostream>

template<class Tmp> Tmp sum(const Tmp& a, const Tmp& b){


return a + b;
}

int main(){
std::cout << _________________; //LINE-1
return 0;
}

Identify the correct statement(s) such that the above program executes successfully.

a) sum(10, 20)

b) sum(10.3, 20.3f)

c) sum(10.3, 20)

d) sum(10, int(’A’))

Answer: a), d)
Explanation:
As per the code both the arguments of sum should be of the same (Temp). Therefore, the
options a) and d) are correct.

8
Question 7
Consider the following code segment. [MCQ, Marks 2]

#include <iostream>

template <typename T, int N> //LINE-1


class NPrint{
public:
NPrint(T v) : _v(v){}
void print(){
for(int i = 0; i < N; i++)
std::cout << _v;
}
private:
T _v;
};
int main(){
int n = 3;
NPrint<char, n> np(’Q’); //LINE-2
np.print();
return 0;
}

What will be the output / error?

a) 333

b) QQQ

c) Compiler error at LINE-1: non-type argument is not allowed

d) Compiler error at LINE-2: non-type argument must be constant

Answer: d)
Explanation:
In C++ template, non-type argument n in template must be a constant.

9
Question 8
Consider the code segment given below. [MCQ, Marks 2]

#include<iostream>
class complex{
public:
complex(int re = 0, int im = 0) : re_(re), im_(im){}
int getRe(){ return re_; }
int getIm(){ return im_; }
void setRe(int re){ re_ = re; }
void setIm(int im){ im_ = im; }
friend std::ostream& operator<<(std::ostream& os, const complex& c);
private:
int re_, im_;
};

std::ostream& operator<<(std::ostream& os, const complex& c){


os << c.re_ << " + i" << c.im_ << std::endl;
return os;
}

template<class T> T add(T x, T y){


return x + y;
}
________________________________ { //LINE-1
complex t;
t.setRe(x.getRe() + y.getRe());
t.setIm(x.getIm() + y.getIm());
return t;
}

int main(){
complex c1(10, 10);
complex c2(5, 15);
std::cout << add<double>(5.5, 1.4) << ", ";
std::cout << add<int>(5, 4) << ", ";
std::cout << add<complex>(c1, c2);
return 0;
}

Identify the appropriate option to fill in the blank at LINE-1 such that the program gives
output as
6.9, 9, 15 + i25

a) complex add(complex x, complex y)

b) template<complex> complex add(complex x, complex y)

c) template<> complex add<complex>(complex x, complex y)

d) template<T> add<complex>(complex x, complex y)

Answer: c)
Explanation:

10
The appropriate statement for template specification for complex at LINE-1 is:
template<> complex add<complex>(complex x, complex y))

11
Question 9
Consider the following code segment. [MCQ, Marks 2]

#include <iostream>

struct statWorld {
statWorld(double m = 0.0) : m_(m) { }
void ______________________________ { //LINE-1
for(int i = 0; i < l; i++)
s += arr[i];
m_ = (double)s / l;
}
double m_; //mean
};

int main(){
int a[] = {1, 2, 3, 4};
int n = sizeof(a) / sizeof(a[0]);
statWorld cl;
int s = 0;
cl(a, n, s);
std::cout << "sum = " << s << ", ";
std::cout << "mean = " << cl.m_ << std::endl;
return 0;
}

Identify the appropriate option to fill in the blank at LINE-1 such that the output becomes

sum = 10, mean = 2.5

a) operator(int arr[], int l, int* s)

b) operator(int arr[], int l, int& s)()

c) operator()(int arr[], int l, int& s)

d) operator()(int arr[], int l, int* s)

Answer: c)
Explanation:
The appropriate header to overload the function operator in this case is option c).

12
Programming Questions

Question 1
Consider the program below.

• Fill in the blank at LINE-1 to specify the fourth argument of the function call, which
accepts correct type of function pointer to each member function of class Computation.

• Fill in the blank at LINE-2 with appropriate return statement.

The program must satisfy the given test cases. Marks: 3

#include <iostream>

class Computation{
public:
int sum(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
};

int call(Computation *obj, int x, int y, ______________){ //LINE-1


return ___________________; //LINE-2
}
int main() {
int a, b;
Computation *c;
std::cin >> a >> b;
std::cout << call(c, a, b, &Computation::sum) << " ";
std::cout << call(c, a, b, &Computation::sub);
return 0;
}

Public 1
Input: 10 20
Output: 30 -10

Public 2
Input: 10 10
Output: 20 0

Private
Input: 20 10
Output: 30 10

13
Answer:
LINE-1: int (Computation::*fpm)(int, int)
LINE-2: (obj->*fpm)(x, y)
Please note that the name function pointer variable (fpm) can have any other valid name.
Explanation:
The correct declaration of function pointer to point to the member functions Computation::sum
or Computation::sub can be:
int (Computation::*fpm)(int, int)
LINE-2 must return the return value of function pointed by fpm, which can be done in the
following manner:
return (obj->*fpm)(x, y)

14
Question 2
Consider the following program that computes the mean of the squares of a number of integers.
Fill in the blanks as per the instructions given below to complete the definition of functor max
with local state:

• Fill in the blank at LINE-1 with constructor header.

• At LINE-2 overload the function call operator.

The program must satisfy the given test cases. Marks: 3

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

struct max {
________________________ : cnt_(cnt), ss_(ss) {} //LINE-1
_________________________________________________ //LINE-2
int cnt_; //count of element
int ss_; //sum of square of emements
};

int main(){
std::vector<int> v;
int n, a;
std::cin >> n;
for(int i = 0; i < n; i++){
std::cin >> a;
v.push_back(a);
}
max mi = for_each(v.begin(), v.end(), max());
std::cout << "mean = " << (double)mi.ss_/mi.cnt_;
return 0;
}

Public 1
Input: 4 1 2 3 4
Output: mean = 7.5

Public 2
Input: 5 10 20 30 40 50
Output: mean = 1100

Private
Input: 4 10 9 8 7
Output: mean = 73.5

Answer:
LINE-1: max(int cnt = 0, int ss = 0)
LINE-2: void operator() (int x) { ++cnt ; ss += x * x; }
Explanation:

15
The constructor must initialize ss = 0 and cnt = 0. Therefore, the constructor header must
be defined as:
max(int cnt = 0, int ss = 0)
The function call operator must be overloaded to find the count of the elements of the array,
and to get the sum of the squares of the elements. Thus, it must be:
void operator() (int x) { ++cnt ; ss += x * x; }

16
Question 3
Consider the following program, which define a type plist that stores N elements. Fill in the
blanks as per the instructions given below:

• Fill in the blank at LINE-1 with appropriate template definition,

• At LINE-2 implement void insert(int i, T val) function, which inserts a value at


specified index; however, if the input index is ≥ N , it throws OutOfArray exception,

• At LINE-3 implement void T peek(int i) function, which returns value of a speci-


fied index. However, if the element at the specified position is negative then it thorws
InvalidElement exception.

The program must satisfy the given test cases. Marks: 3

#include<iostream>

class OutOfArray{
public:
virtual void what(){ std::cout << "index out of array"; }
};

class InvalidElement{
public:
virtual void what(){ std::cout << "invalid"; }
};

_____________________________________ //LINE-1
class plist{
public:
plist(){
for(int i = 0; i < N; i++)
arr_[i] = -1;
}
//LINE-2: impelement insert() function

//LINE-3: impelement peek() function

private:
T arr_[N];
};

int main(){
int n;
char c;
plist<char, 4> li;
try{
for(int i = 0; i < 4; i++){
std::cin >> n;
std::cin >> c;
li.insert(n, c);
}
}catch(OutOfArray& e){

17
e.what();
std::cout << std::endl;
}
for(int i = 0; i < 4; i++){
try{
std::cout << li.peek(i) << ", ";
}catch(InvalidElement& e){
e.what();
std::cout << ", ";
}
}
return 0;
}

Public 1
Input: 1 a 2 b 3 c 0 x
Output: x, a, b, c,

Public 2
Input: 2 a 1 x 3 z 2 y
Output: invalid, x, y, z,

Public 3
Input: 0 a 2 b 3 x 4 z
Output:
index out of array
a, invalid, b, x,

Public 4
Input: 0 a 6 x
Output:
index out of array
a, invalid, invalid, invalid,

Private
Input: 0 x 2 y 3 z 2 a
Output: x, invalid, a, z,

Answer:
LINE-1: template<typename T, int N>
or
LINE-1: template<class T, int N>
LINE-2:
void insert(int i, T val){
if(i < N)
arr_[i] = val;
else
throw OutOfArray();
}

18
LINE-3:

T peek(int i){
if(arr_[i] < 0)
throw InvalidElement();
return arr_[i];
}

Explanation:
At LINE-1, the template definition must be:
template<typename T, int N>
or
LINE-1: template<class T, int N>
At LINE-2, define the void insert(int i, T val) to add element val at index i as follows:

void insert(int i, T val){


if(i < N)
arr_[i] = val;
else
throw OutOfArray();
}

At LINE-3, define the T peek(int i) to return the element at index i as follows:

T peek(int i){
if(arr_[i] < 0)
throw InvalidElement();
return arr_[i];
}

19
Programming in Modern C++: Assignment Week 9
Total Marks : 25

Partha Pratim Das


Department of Computer Science and Engineering
Indian Institute of Technology Kharagpur, Kharagpur – 721302
partha.p.das@gmail.com

March 12, 2024

Question 1
Consider the following program. [MCQ, Marks 2]

#include<cstdio>
using namespace std;

int main(){
int n = 0x0043;
printf("%d %o %x %c", n, n, n, n);
return 0;
}

What will be the output/error?

a) 43 43 43 43

b) 67 103 43 C

c) 67 103 43 67

d) Compiler error at LINE-1: type cast from int -> char is invalid

Answer: b)
Explanation:
The integer n = 0x0043 is assigned to a hexadecimal value. The corresponding decimal value
is 67.
Therefore, n is printed as %d (i.e. in decimal format), which is 67.
n is printed as %o (i.e. in octal format), which is 103.
n is printed as %x (i.e. in hexadecimal format), which is 43.
n is printed as %c (i.e. as a char), which is ’C’.

1
Question 2
Consider the code segment given below. [MCQ, Marks 2]

#include<cstdio>
using namespace std;

int main(){
FILE *ifp, *ofp;
int c;
if((ifp = fopen("a.txt", "r")) == NULL)
return 1;
if((ofp = fopen("b.txt", "w")) == NULL)
return 2;
while((c = getc(ifp)) != EOF) {
if(c == ’\n’);
else
fputc(c, ofp);
}
fclose(ifp);
fclose(ofp);
return 0;
}

Choose the correct statement about execution of the given code.

a) It copies all the lines from a.txt to b.txt.

b) It copies all the lines from a.txt to b.txt; however, merge all the lines to a single line.

c) It copies all newline characters of a.txt to b.txt.

d) It copies all lines except the last line of a.txt to b.txt.

Answer: b)
Explanation:
During the copy from a.txt to b.txt, the code skip the newline characters. Therefore, It
copies all the lines from a.txt to b.txt; however, merge all the lines to a single line.

2
Question 3
Consider the following code segment. [MCQ, Marks 2]

#include <iostream>
#include <iomanip>

int main () {
std::cout.precision(4);
std::cout << std::setfill (’0’) << std::setw (8) << (double)10/3;
return 0;
}

What will be the output?

a) 3.333333

b) 3.333000

c) 0003.333

d) 003.3333

Answer: c)
Explanation:
The statement std::cout.precision(4); prints up to 3 digits after decimal point.
The statement std::setw (8) set the width of the number as 8 including the decimal point.
The statement std::setfill (’0’) fills the empty spaces with 0.
Therefore, option c) is correct.

3
Question 4
Consider the code given below that verifies existence of a file myfile.txt in given path. [MCQ,
Marks 2]

#include <iostream>
#include <fstream>

int main () {
std::ifstream fl("c:\\code\\myfile.txt");
if (______________) { //LINE-1
std::cout << "file does not exist";
}
else{
std::cout << "file exists";
fl.close();
}
return 0;
}

Identify the appropriate option to fill in the blank at LINE-1 such that it checks if the file does
not exist.

a) fl.is open()

b) !fl.is open()

c) !fl.open()

d) fopen(fl) == NULL

Answer: b)
Explanation:
Since the program attempts to read from the file, if the file exists or not can be verified by
is open() function. Thus, the correct option is b).

4
Question 5
Match the appropriate descriptions about the fseek function calls.
Here, infp is a file pointer pointing to the beginning of a file in read-write mode. [MCQ,
Marks 2]
Function call Description
1. fseek(infp, 10, SEEK SET) A. Moves the file pointer to the beginning of the file
2. fseek(infp, -10, SEEK CUR) B. Moves the file pointer forward from the beginning
of the file by 10 positions
3. fseek(infp, -10, SEEK END) C. Moves the file pointer backwards from the current position
in the file by 10 positions
4. fseek(fp, 0, SEEK SET) D. Moves the file pointer backwards from the end
of the file by 10 positions

a) 1-C, 2-A, 3-B, 4-D

b) 1-C, 2-B, 3-A, 4-D

c) 1-B, 2-C, 3-D, 4-A

d) 1-B, 2-D, 3-C, 4-A

Answer: d)
Explanation:

• fseek(infp, 10, SEEK SET) moves the file pointer forward from the beginning of the
file by 10 positions.

• fseek(infp, -10, SEEK CUR) Moves the file pointer backwards from the current posi-
tion in the file by 10 positions.

• fseek(infp, -10, SEEK END) Moves the file pointer backwards from the end of the file
by 10 positions.

• fseek(fp, 0, SEEK SET) Moves the file pointer to the beginning of the file.

5
Question 6
Consider the following code segment. [MSQ, Marks 2]

#include<iostream>
#include<algorithm>
#include<list>

int main() {
int ai[] = {1, 2, 3, 4, 5, 6, 7};
std::list<int> li(3);
_____________________________________; //LINE-1
for (std::list<int>::iterator it = li.begin(); it != li.end(); ++it)
std::cout << *it << " ";
return 0;
}

Identify the appropriate call to copy function to fill in the blank at LINE-1 such that the
output is:
3 4 5

a) std::copy (ai + 3, ai + 6, li.begin())

b) std::copy (ai + 2, ai + 5, li.begin())

c) std::copy (&ai[0], &ai[6], li.begin() + 3)

d) std::copy (&ai[2], &ai[5], li.begin())

Answer: b), d)
Explanation:
The syntax of copy function is as follows:

template<class InputIterator, class OutputIterator>


OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result)

The correct options are b) and d).

6
Question 7
Consider the code segment below that computes the sum of difference between two vectors.
[MCQ, Marks 2]

#include <iostream>
#include <functional>
#include <numeric>
#include <vector>

int operation1(int x, int y){


return x - y;
}

int operation2(int x, int y){


return x + y;
}

int compute(std::vector<int> v1, std::vector<int> v2, int init){


return ____________________________________________; //LINE-1
}
int main(){
std::vector<int> vi1 = { 11, 22, 33 };
std::vector<int> vi2 = { 1, 2, 3 };

std::cout << compute(vi1, vi2, 0);

return 0;
}

Choose the correct option to fill in the blank at LINE-1 such that the output is 60.

a) std::inner product(v1.begin(), v1.end(), v2.begin(), operation1, init, operation2)

b) std::inner product(v1.begin(), v1.end(), v2.begin(), init, operation1, operation2)

c) std::inner product(v1.begin(), v1.end(), v2.begin(), init, operation2, operation1)

d) std::inner product(v1.begin(), v1.end(), v2.begin(), init, operation2(operation1))

Answer: c)
Explanation:
The code by inner product function is:

template<class In, class In2, class T, class BinOp, class BinOp2 >
T inner_product(In first, In last, In2 first2, T init, BinOp op1, BinOp2 op2) {
while(first!=last) {
init = op1(init, op2(*first, *first2));
++first; ++first2;
}
return init;
}

Thus, c) is the correct option.

7
Question 8
Consider the following code segment. [MSQ, Marks 2]

#include<iostream>
#include<vector>

template<typename Itr, typename T>


______________________________________ { //LINE-1
int minpos = 0, i = 0;
mval = *first++;
while (first != last) {
if(*first < mval){
mval = *first;
minpos = i + 1;
}
++first;
++i;
}
return minpos;
}

int main(){
std::vector<int> vi = { 3, 2, 6, 1, 6, 8, 7};
int mVal = 0;
int pos = findmin(vi.begin(), vi.end(), mVal);
std::cout << pos << " : " << mVal;
return 0;
}

Identify the correct function header(s) for findmin to fill in the blank at LINE-1 such that the
program finds out the minimum element of the vector vi and the output is 3 : 1.

a) int findmin(Itr first, Itr last, T mval)

b) int findmin(Itr first, Itr last, T& mval)

c) int findmin(T first, T last, Itr& mval)

d) int findmin(Itr first, T last, T& mval)

Answer: b), c)
Explanation:
The actual parameters of the function findmin are as follows:

• vi.begin() and vi.end(): Return iterators pointing to the first element and last ele-
ment in the vector.

• mval: Must be pass-by-reference to store the minimum element of the vector.

And it returns the index of the minimum element. Therefore, option b) and c) are the correct
options.

8
Question 9
Consider the code segment below. [MCQ, Marks 2]

#include <iostream>
#include <vector>
#include <numeric>
#include <functional>

double fun(double x, double y){


return x * y;
}

double compute(std::vector<int>& li) {


double result = std::accumulate(li.begin(), li.end(), 0.5, fun); //LINE-1
return result;
}

int main() {
int arr[] = { 10, 20, 30, 40 };
std::vector<int> vi(arr, arr + sizeof(arr) / sizeof(*arr));
std::cout << compute(vi);
return 0;
}

What will be the output?

a) 0

b) 600

c) 120000

d) 240000

Answer: c)
Explanation:
The function accumulate in the following manner.

template<class In, class T, class BinOp> T accumulate(In first, In last, T init,


BinOp op) {
while (first!=last) {
init = op(init, *first); // means "init op *first"
++first;
}
return init;
}

Since init = 0.5, the code computes half of the production of the elements from the vector
vi.

9
Programming Questions

Question 1
Consider the following program which takes name and rank of some players, followed by the
type of sorting (1 for sort by the length of name and 2 for sort by rank) as input. It prints
the players’ information in the corresponding sorted order. Complete the program with the
following instructions.

• Fill the missing code segments at code-segment-1 and code-segment-2 with the ap-
propriate overriding of function operator.

The program must satisfy the sample input and output. Marks: 3

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

class player{
public:
player(int rank, std::string name) : rank_(rank), name_(name){}
int get_rank(){ return rank_; }
std::string get_name(){ return name_; }
private:
int rank_;
std::string name_;
};

struct cmpByName{
//code-segment-1
};

struct cmpByRank{
//code-segment-2
};

int main() {
int a, c;
std::string b;

std::vector<player> pv;
for(int i = 0; i < 4; i++){
std::cin >> a >> b;
player p(a, b);
pv.push_back(p);
}

std::cin >> c;
if(c == 1)
std::sort(pv.begin(), pv.end(), cmpByRank());
else if(c == 2)
std::sort(pv.begin(), pv.end(), cmpByName());
for(std::vector<player>::iterator it = pv.begin(); it < pv.end(); it++)

10
std::cout << it->get_rank() << " : " << it->get_name() << std::endl;
return 0;
}

Public 1
Input:
20 raj
10 dilip
30 subendu
40 nalini
1
Output:
10 : dilip
20 : raj
30 : subendu
40 : nalini

Public 2
Input:
20 raj
10 dilip
30 subendu
40 nalini
2
Output:
20 : raj
10 : dilip
40 : nalini
30 : subendu

Private
Input:
3 livin
2 shivani
1 piyush
4 nitin
2
Output:
3 : livin
4 : nitin
1 : piyush
2 : shivani

Answer:

code-segment-1:
bool operator()(player p1, player p2){
return p1.get_name().size() < p2.get_name().size();
}

11
code-segment-2:
bool operator()(player p1, player p2){
return p1.get_rank() < p2.get_rank();
}

Explanation:
At code-segment-1, the overloading of the function operator that sorts the players by the
length of name can be done as follows:

bool operator()(player p1, player p2){


return p1.get_name().size() < p2.get_name().size();
}

At code-segment-2, the overloading of the function operator that sorts the players by rank
can be done as follows:

bool operator()(player p1, player p2){


return p1.get_rank() < p2.get_rank();
}

12
Question 2
Consider the following program, which takes 10 numbers as input, and computes the frequency
of each number. Fill in the blanks as per the instructions given below:

• at LINE-1 with appropriate statement to iterate over the given list li,

• at LINE-2 with appropriate statement to iterate over the given map fq,

such that it will satisfy the given test cases. Marks: 3

#include <iostream>
#include <map>
#include <list>

std::map<int, int> findFrequency(std::list<int> li){


std::map<int, int> fqMap;
for (_______________________________________) //LINE-1
fqMap[*it]++;
return fqMap;
}

void print(std::map<int, int> fq){


for (___________________________________) //LINE-2
std::cout << it->first << " => " << it->second << ", ";
}

int main() {
std::list<int> li;
int a;
for(int i = 0; i < 10; i++){
std::cin >> a;
li.push_back(a);
}
std::map<int, int> fq = findFrequency(li);
print(fq);
return 0;
}

Public 1
Input: 10 30 50 20 30 40 50 10 20 10
Output: 10 => 3, 20 => 2, 30 => 2, 40 => 1, 50 => 2,

Public 2
Input: 10 20 10 30 10 40 10 50 20 30
Output: 10 => 4, 20 => 2, 30 => 2, 40 => 1, 50 => 1,

Private
Input: 10 20 30 40 50 40 20 30 10 10
Output: 10 => 3, 20 => 2, 30 => 2, 40 => 2, 50 => 1,

13
Answer:
LINE-1: std::list<int>::iterator it = li.begin(); it != li.end(); ++it
LINE-2: std::map<int, int>::iterator it = fq.begin(); it != fq.end(); ++it
Explanation:
The std::list<int>::iterator type can be used to iterate through the given list li, so the
statement at LINE-1 ca be:
for (std::list<int>::iterator it = li.begin(); it != li.end(); ++it)
Similarly, the std::map<int, int>::iterator type can be used to iterate through the given
map fq, so the statement at LINE-2 can be:
for (std::map<int, int>::iterator it = fq.begin(); it != fq.end(); ++it)

14
Question 3
Consider the following program that filters the elements from a given list li within a given
upper and lower bounds and prints them.

• Fill in the blanks at LINE-1 with appropriate template declaration.

• Fill in the blanks at LINE-2 with an appropriate condition of the while loop.

• Fill in the blanks at LINE-3 with an appropriate call to function find if such that it
returns an iterator object to the first element from li that match the given predicate
with upper and lower bounds.

The program must satisfy the sample input and output. Marks: 3

#include<iostream>
#include<list>

template<typename T>
struct boundIt{
T ub_, lb_;
boundIt(T lb = 0, T ub = 0) : ub_(ub), lb_(lb) { }
bool operator()(T x){ return (x <= ub_ && x >= lb_); }
};

__________________________________ //LINE-1
T find_if(T first, T last, Pred prd) {
while (_____________________________) ++first; //LINE-2
return first;
}

void print(std::list<int> li, int lb, int ub){


boundIt<int> bnd(lb, ub);
__________________________________________________; //LINE-3
while(it != li.end()){
std::cout << *it << " ";
it = find_if(++it, li.end(), bnd);
}
}

int main(){
std::list<int> li {30, 70, 10, 40, 20, 50, 60, 80};
int l, u;
std::cin >> l >> u;
print(li, l, u);
return 0;
}

Public 1
Input: 30 55
Output: 30 40 50

15
Public 2
Input: 20 80
Output: 30 70 40 20 50 60 80

Private
Input: 50 88
Output: 70 50 60 80

Answer:
LINE-1: template<typename T, typename Pred>
or
LINE-1: template<class T, class Pred>
LINE-2: first != last && !prd(*first)
LINE-3: std::list<int>::iterator it = find if(li.begin(), li.end(), bnd)
Explanation:
At LINE-1, the function the appropriate funcition template is:
template<typename T, typename Pred>
or
template<class T, class Pred>
At LINE-2, the while loop condition must be:
first != last && !prd(*first)
At LINE-3, the first element match the predicate can be find out as:
std::list<int>::iterator it = find if(li.begin(), li.end(), bnd)

16
Programming in Modern C++: Assignment Week 10
Total Marks : 25

Partha Pratim Das


Department of Computer Science and Engineering
Indian Institute of Technology Kharagpur, Kharagpur – 721302
partha.p.das@gmail.com

March 20, 2024

Question 1
Consider the code segment (in C++11) given below. [MSQ, Marks 2]

#include<iostream>
int main( ){
int n = 10;
int& rn = n;
______ tn = rn; //LINE-1

++tn;
std::cout << n << " " << rn << " " << tn;
return 0;
}

Identify the appropriate option/s to fill in the blank at LINE-1 such that output becomes
10 10 11

a) auto

b) auto&

c) decltype(rn)

d) decltype((n))

Answer: a)
Explanation:
Since auto never deduces adornments like cv-qualifer or reference, in option a) the inferred
type of tn is int. Thus, output will be 10 10 11.
In option b) the inferred type of tn is int&. Thus, output will be 11 11 11.
In option c) the inferred type of tn is the type of rn that is int&. Thus, output will be 11 11
11.
In option d) the inferred type of t is the type of reference to n that is int&. Thus, output will
be 11 11 11.
Intentionally kept as MSQ

1
Question 2
Consider the code segment (in C++11) given below. [MSQ, Marks 2]

#include <iostream>

int main( ){
int arr[] = { 1, 2, 3, 4, 5 };
for(________________ : arr) // LINE-1
i *= 2;

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


std::cout << arr[i] << " ";
return 0;
}

Identify the appropriate option(s) to fill in the blank at LINE-1 such that the output of the
program is NOT: 2 4 6 8 10

a) auto i

b) auto& i

c) decltype(*arr) i

d) decltype(arr[0]) i

Answer: a)
Explanation:
In option a), the inferred type of i is int. Thus, the changes made in i are not reflected in
the array arr. So, the O/P is 1 2 3 4 5
In option b), the inferred type of i is int&. Thus, the changes made in i are reflected in the
array arr.
In option c), the inferred type of i is the output of decltype(*arr) i.e. int&. Thus, the
changes made in i are reflected in the array arr. In option d), the inferred type of i is the
output of decltype(arr[0]) i.e. int&. Thus, the changes made in i are reflected in the array
arr.
Intentionally kept as MSQ.

2
Question 3
Consider the following code segment. [MSQ, Marks 2]

#include <iostream>

class data{
public:
constexpr data(int n = 0) : n_{n} { }
private:
int n_;
};

const int num_gen1(){


return 1;
}

constexpr int num_gen2(const int i){


return i + 10;
}

int main(){
int i = 10;
const int j = 20;
constexpr data d1(1); //LINE-1
constexpr data d2(i); //LINE-2
constexpr data d3(num_gen1()); //LINE-3
constexpr data d4(num_gen2(j)); //LINE-4
return 0;
}

Which of the following line/s generate/s compiler error?

a) LINE-1

b) LINE-2

c) LINE-3

d) LINE-4

Answer: b), c)
Explanation:
At LINE-1, the constructor parameter is constant from the compile time context. Thus, the
object can be constexpr.
At LINE-2, the constructor parameter is non-const. Thus, the object can not be of constexpr.
At LINE-3, the constructor parameter is the return value of the num gen1() function. However,
the return type of num gen1() is not constexpr, therefore the object cannot be constexpr.
At LINE-4, the constructor parameter is the return value of the num gen2(int) function.
However, the return type of it is constexpr, therefore the object can be constexpr.

3
Question 4
Consider the program (in C++11) given below. [MSQ, Marks 2]
#include <iostream>
constexpr double pi = 3.14;

namespace v1_0 {
class circle{
public:
circle(int r) : r_(r) {}
double area(){ return pi * r_ * r_; }
private:
int r_;
};
}

inline namespace v2_0 {


template<typename T>
class circle{
public:
circle(T r) : r_(r) {}
double area(){ return pi * r_ * r_; }
private:
T r_;
};
}

int main(){
____________ c1(10.5); //LINE-1
____________ c2(10.5); //LINE-2
____________ c3(10.5); //LINE-3
std::cout << c1.area() << " " << c2.area() << " " << c3.area();
return 0;
}
Choose the appropriate option to fill in the blanks at LINE-1, LINE-2, and LINE-3 so that the
program runs without any compilation error and produces the output:
314 314 346.185
a) LINE-1: circle
LINE-2: circle<int>
LINE-3: circle<double>

b) LINE-1: v1 0::circle
LINE-2: v2 0::circle<int>
LINE-3: circle<double>

c) LINE-1: v1 0::circle
LINE-2: circle<int>
LINE-3: circle<double>

d) LINE-1: v2 0::circle
LINE-2: v2 0::circle<int>
LINE-3: v2 0::circle<double>

4
Answer: b), c)
Explanation:
Since namespace v2 0 is declared as inline and it defines the templated version of class circle,
the templated class circle can be instantiated with or without namespace resolution. How-
ever, for namespace v1 0 (defines the non-templated version of circle), namespace resolution
is not mandated.

5
Question 5
Consider the following code segment (in C++11). [MSQ, Marks 2]

#include<iostream>
#include<iomanip>
constexpr double cr = 12.0;

long double operator"" _FT(long double l) {


return l;
}
long double operator"" _IN(long double l) {
return cr * l;
}
class length{
public:
length(double l1 = 0, double l2 = 0) : l1_(l1), l2_(l2){}
int operator()(){ return l1_ + l2_; }
private:
int l1_, l2_;
};
int main() {
length len(______, _______); //LINE-1
std::cout << len() << "IN";
return 0;
}

Choose the appropriate option to fill in the blank at LINE-1 such that the output is 125IN.

a) 5.0FT, 10.0IN

b) (FT)5, (IN)10

c) 5.0 FT, 10.0 IN

d) 5 FT, 11 IN

Answer: c)
Explanation:
For user-defined numeric literal operators, the correct way to invoke them is to write them as
5.0 FT, 10.0 IN.
All other options are compilation error. Even option d) is wrong as numeric literal operators
require exact type matching.
Intentionally kept as MSQ

6
Question 6
Consider the following program (in C++11). [MCQ, Marks 2]

#include<iostream>
class A{
public:
A(const int& n) { std::cout << "#1 " ; }
A(const A& ob) { std::cout << "#2 " ; }
A(A&& ob) noexcept { std::cout << "#3 " ; }
};

class B : public A {
public:
B(const int& n, const int& m) : A(n) { std::cout << "#4 " ; }
B(const B& ob) : A(ob) { std::cout << "#5 " ; }
B(B&& ob) noexcept : A(ob) { std::cout << "#6 " ; }
};

int main(){
B b1(1, 2);
B b2(b1);
B b3 = std::move(b1);
return 0;
}

What will be the output?

a) #1 #4 #2 #5 #3 #6

b) #1 #4 #2 #5 #2 #6

c) #1 #4 #2 #5 #3 #5

d) #1 #4 #2 #6 #2 #6

Answer: b)
Explanation:
The statement b1(100, 200) invokes the parameterized constructor of B class, which forwards
the call to the parameterized constructor of A class. It prints #1 #4.
The statement B b2(b1) invokes the copy constructor of B class, which forwards the call to
the copy constructor of A class. It prints #2 #5.
The statement B b3 = std::move(b1); invokes the move constructor of B class, which (how-
ever) forwards the call to the copy constructor of A class. It prints #2 #6.

7
Question 7
Consider the code segment (C++11) given below. [MCQ, Marks 2]

#include <iostream>
#include <initializer_list>

template<typename T>
class items{
public:
items() { std::cout << "cont-1 "; }
items(char c) { std::cout << "cont-2 "; }
items(std::initializer_list<T> elms) { std::cout << "cont-3 "; }
items(char c, std::initializer_list<T> elms) { std::cout << "cont-4 "; }
};
int main(){
items<char> c1(’a’);
items<char> c2({’a’, ’b’, ’c’});
items<char> c3{’a’, ’b’, ’c’};
items<char> c4 = {’a’, ’b’, ’c’};
items<char> c5(’d’, {’a’, ’b’, ’c’});
return 0;
}

What will be the output?

a) cont-3 cont-3 cont-3 cont-3 cont-3

b) cont-2 cont-2 cont-3 cont-2 cont-4

c) cont-2 cont-3 cont-3 cont-3 cont-4

d) cont-2 cont-2 cont-3 cont-3 cont-3

Answer: c)
Explanation:
c1(’a’) invokes parameterized constructor items(char c) { ... }.
c2({’a’, ’b’, ’c’)}, c3{’a’, ’b’, ’c’} and c4 = {’a’, ’b’, ’c’} invoke the initializer
list constructor items(std::initializer list<T> elms){ ... }.
c5(’d’, {’a’, ’b’, ’c’}) invokes the mixed constructor
items(char c, std::initializer list<T> elms){ ... }.

8
Question 8
Consider the following code segment. [MSQ, Marks 2]

#include <iostream>

void print(char* str){ /*some code*/ }

template<typename Fun, typename Param>


void caller(Fun func, Param p){
func(p);
}

int main(){
char s[2] = "0";
caller(print, s); //LINE-1
caller(print, 0); //LINE-2
caller(print, s[1]); //LINE-3
caller(print, nullptr); //LINE-4
return 0;
}

Which of the following lines generate/s compiler error?

a) LINE-1

b) LINE-2

c) LINE-3

d) LINE-4

Answer: b), c)
Explanation:
For the call in LINE-1, the template type parameter Param is deduced to char*. Thus, it does
not generate any compiler error.
For the call in LINE-2, the template type parameter Param is deduced to int. Thus, it gener-
ates a compiler error.
For the call in LINE-3, the template type parameter Param is deduced to char. Thus, it gen-
erates a compiler error.
For the call in LINE-4, the template type parameter Param is deduced to std::nullptr t and
the call print(std::nullptr t) is syntactically correct.

9
Question 9
Consider the code segment (in C++14) given below. [MSQ, Marks 2]

#include<iostream>
struct double_it{
int n_;
double_it(int n) : n_(2 * n){}
int operator()() { std::cout << "lval "; return n_; }
};

struct triple_it{
int n_;
triple_it(int n) : n_(3 * n){}
int& operator()() { std::cout << "rval "; return n_; }
};

template < typename T >


_______________________________________ { //LINE-1
return op() ;
}

int main(){
double_it o1{10};
triple_it o2{10};
std::cout << wrapper(o1) << " ";
std::cout << (wrapper(o2) = 20);
return 0;
}

Identify the appropriate option/s to fill in the blank at LINE-1 such that output becomes
lval 20 rval 20.

a) decltype(op()) wrapper( T& op )

b) auto wrapper( T& op ) -> decltype(op())

c) auto wrapper( T& op )

d) decltype(auto) wrapper( T& op )

Answer: b), d)
Explanation:
The call wrapper(o1) evaluates to prvalue of type int.
The call wrapper(o2) = 20 evaluates to lvalue of type int&.
Therefore, the function wrapper requires training return type declaration, which can be done
in two ways:
auto wrapper( T& op ) -> decltype(op()) in C++11, and
decltype(auto) wrapper( T& op ) in C++14.

10
Programming Questions

Question 1
Consider the following program (in C++14).
• Fill in the blank at LINE-1 with an appropriate template definition.
• Fill in the blank at LINE-2 with an appropriate header for function divide.
The program must satisfy the sample input and output. Marks: 3
#include <iostream>

int convert(double d){


return int(d);
}
double convert(int i){
return double(i);
}

___________________________________ //LINE-1
___________________________________ { //LINE-2
return convert(n1) / convert(n2);
}
int main(){
int a, b;
double c, d;
std::cin >> a >> b >> c >> d;
std::cout << divide(a, b) << " ";
std::cout << divide(a, c) << " ";
std::cout << divide(c, d);
return 0;
}

Public 1
Input: 50 40 30 20
Output:
1.25 1.66667 1

Public 2
Input: 10 6 3 2
Output: 1.66667 3.33333 1

Private
Input: 100 50 70 80
Output: 2 1.42857 0

Answer:
In C++11
LINE-1: template<typename T1, typename T2>
LINE-2: auto divide(T1 n1, T2 n2) -> decltype(convert(n1) / convert(n2))

11
or in C++14

LINE-2: decltype(auto) divide(T1 n1, T2 n2)

Explanation:
Since we can pass two different types of parameters in divide function, we can write at LINE-1:
template<typename T1, typename T2>
The header for function divide in C++11 should be:
auto divide(T1 n1, n2 n2) -> decltype(convert(n1) / convert(n2))
And in C++14:
decltype(auto) divide(T1 n1, T2 n2)
Please any other legal identifier can be used for the typed-parameters.

12
Question 2
Consider the following program (in C++11).

• Fill in the blank at LINE-1 with appropriate header and initialization list for copy con-
structor.

• Fill in the blank at LINE-2 with appropriate header for overloading copy assignment
operator.

• Fill in the blank at LINE-3 with appropriate header and initialization list for move
constructor.

• Fill in the blank at LINE-4 with appropriate header for overloading move assignment
operator.

The program must satisfy the sample input and output. Marks: 3

#include <iostream>

class ctype {
public:
ctype() : cp_(nullptr) { }
ctype(char c) : cp_(new char(c)) { }
__________________________ {} // LINE-1: copy constructor
_________________ { // LINE-2: copy assignment
if (this != &ob) {
delete cp_;
cp_ = new char(*(ob.cp_) + 1);
}
return *this;
}
____________________ { // LINE-3: move constructor
ob.cp_ = nullptr;
}
______________ { // LINE-4: move assignment
if (this != &ob) {
cp_ = ob.cp_;
ob.cp_ = nullptr;
}
return *this;
}
void print(){
if(cp_ == nullptr)
std::cout << "moved, ";
else
std::cout << *cp_ << ", ";
}
~ctype() { delete cp_; }
private:
char* cp_ = nullptr;
};
int main(){
char a;

13
std::cin >> a;

ctype c1(a); ctype c2 = c1;


ctype c3 = c1;

c1.print(); c2.print(); c3.print();

ctype c4 = std::move(c1);
ctype c5; c5 = std::move(c1);
c1.print(); c4.print(); c5.print();

return 0;
}

Public 1
Input: A
Output: A, A, A, moved, A, moved,

Public 2
Input: X
Output: X, X, X, moved, X, moved,

Private
Input: z
Output: z, z, z, moved, z, moved,

Answer:
LINE-1: ctype(const ctype& ob) : cp (new char(*(ob.cp )))
LINE-2: ctype& operator=(const ctype& ob)
LINE-3: ctype(ctype&& ob) : cp (ob.cp )
LINE-4: ctype& operator=(ctype&& ob)
Explanation:
At LINE-1, the header and initialization list for copy constructor can be written as:
ctype(const ctype& ob) : cp (new char(*(ob.cp )))
At LINE-2, the header for overloading copy assignment operator can be written as:
ctype& operator=(const ctype& ob)
At LINE-3, the header and initialization list for move constructor can be written as:
ctype(ctype&& ob) : cp (ob.cp )
At LINE-4, the header for overloading move assignment operator can be written as:
ctype& operator=(ctype&& ob)

14
Question 3
Consider the following program (in C++11). Fill in the blanks as per the instructions given
below:

• Fill in the blank at LINE-1 with an appropriate template definition.

• Fill in the blank at LINE-2 to complete the header for function add.

• Fill in the blank at LINE-3 to define the new type Tmp.

The program must satisfy the sample input and output. Marks: 3

#include <iostream>

class compex_num{
public:
explicit compex_num(double r = 0, double i = 0) : r_(r), i_(i){}
compex_num operator+(double n){
compex_num res;
res.r_ = this->r_ + n;
res.i_ = this->i_;
return res;
}
compex_num operator+(compex_num c){
compex_num res;
res.r_ = this->r_ + c.r_;
res.i_ = this->i_ + c.i_;
return res;
}
friend std::ostream& operator<<(std::ostream& os, const compex_num& c);
private:
double r_, i_;
};
std::ostream& operator<<(std::ostream& os, const compex_num& c){
os << c.r_ << " + j" << c.i_;
return os;
}

________________________ //LINE-1
________________________ { //LINE-2
______________________________; // LINE-3: define new type Tmp
Tmp sum = n1 + n2;

std::cout << sum << std::endl;


}

int main(){
int a, b, r1, i1, r2, i2;
std::cin >> a >> b >> r1 >> i1 >> r2 >> i2;
compex_num c1(r1, i1);
compex_num c2(r2, i1);
add(c1, a);
add(c1, c2);

15
add(a, b);
return 0;
}

Public 1
Input: 10 20 30 40 50 -60
Output:
40 + j40
80 + j80
30

Public 2
Input: -1 2 3 4 -2 -4
Output:
2 + j4
1 + j8
1

Private
Input: -1 -3 0 1 -1 1
Output:
-1 + j1
-1 + j2
-4

Answer:
LINE-1: template<typename T, typename U>
Or
LINE-1: template<class T, class U>
LINE-2: void add(T& n1, U& n2)
LINE-3: typedef decltype(n1 + n2) Tmp
Explanation:
At LINE-1 the appropriate template can be defined as:
template<typename T, typename U>
or template<class T, class U>
At LINE-2 the header for function add can be written as:
void add(T& n1, U& n2)
At LINE-3 the new type Tmp can be created as:
typedef decltype(n1 + n2) Tmp

16
Programming in Modern C++: Assignment Week 11
Total Marks : 25

Partha Pratim Das


Department of Computer Science and Engineering
Indian Institute of Technology Kharagpur, Kharagpur – 721302
partha.p.das@gmail.com

March 27, 2024

Question 1
Consider the code segment (in C++11) given below. [MSQ, Marks 2]

template <typename T>


class CData {
public:
Data(Data&& obj); //LINE-1
void f1(T&& v); //LINE-2
template <class U>
void f2(U&& v); //LINE-3
template<class V>
void f3(std::vector<V>&& v); //LINE-4
//some more code
private:
T val_;
};

From among the following identify the line(s) which use(s) parameter passing with a universal
reference.

a) LINE-1

b) LINE-2

c) LINE-3

d) LINE-4

Answer: c)
Explanation:
Note that && usually indicates rvalue reference. && indicates a universal reference only where
type deduction takes place.
At LINE-1, no type deduction takes place, therefore && at LINE-1 is just a rvalue reference,
not a universal reference.
At LINE-2, no type deduction takes place since the type deduction for T took place at the
time of class instantiation. Therefore && at LINE-2 is just a rvalue reference, not a universal
reference.
At LINE-3, the template type parameter U requires type deduction. Thus, && at LINE-3

1
indicates a universal reference.
At LINE-4, the template type parameter V requires type deduction. However, since the form of
function parameter is not V&& (it in form std::vector<V>&&), it indicates only rvalue reference.
&& indicates a universal reference only where template type deduction takes place. However,
if no type deduction takes place, then it is just rvalue reference, not universal reference. Thus,
b) is the correct option.
Intentionally made as MSQ

2
Question 2
Consider the program (in C++11) given below. [MSQ, Marks 2]

#include <iostream>

class base1 {
public:
base1(const int& n) { std::cout << "base1 - lvalue : " << n << ", "; }
base1(int&& n) { std::cout << "base1 - rvalue : " << n << ", "; }
};

class base2 {
public:
base2(const int& n) { std::cout << "base2 - lvalue : " << n << ", "; }
base2(int&& n) { std::cout << "base2 - rvalue : " << n << ", "; }
};

class derived : public base1, public base2{


public:
template<typename T1, typename T2>
derived(T1&& n1, T2&& n2) : _________________________ { } //LINE-1
};
int main(){
int i = 10;
derived b1(i, std::move(i));
return 0;
}

Choose the appropriate option to fill in the blank at LINE-1 so that the output becomes
base1 - lvalue : 10, base2 - rvalue : 10,

a) base1(n1), base2(n2)

b) base1(n1), base2(std::forward<T2>(n2))

c) base1(std::forward<T1>(n1)), base2(n2)

d) base1(std::forward<T1>(n1)), base2(std::forward<T2>(n2))

Answer: b), d)
Explanation:
From the output, we can understand that for class base1 the l-value version of the constructors
and for class base2 the r-value version of the constructors need to be called. Since at the
constructor of class derived, n1 and n2 are received as universal reference types, n1 can be
forwarded to class base1 constructor as base(n1) or as base(std::forward<T>(n1)), but n2
needs to be forwarded to class base2 constructor as base2(std::forward<T>(n2)).

3
Question 3
Consider the following code segment (in C++11). [MSQ, Marks 2]

enum class METAL {GOLD, SILVER, TITANIUM, PLATINUM};


enum class CCARD {GOLD, SILVER, TITANIUM, PLATINUM};
enum {GOLD, SILVER, TITANIUM, PLATINUM};

bool check1(METAL type){


return type == METAL::GOLD ? true : false; //LINE-1
}

bool check2(METAL type){


return type == CCARD::SILVER ? true : false; //LINE-2
}

bool check3(METAL type){


type == TITANIUM ? true : false; //LINE-3
}

Identify the statement/s which are true for the above code segment.

a) It generates compilation error at LINE-1

b) It generates compilation error at LINE-2

c) It generates compilation error at LINE-3

d) There is no error in the given code segment

Answer: b), c)
Explanation:
At LINE-1, the statement type == METAL::GOLD compares between two METAL type elements,
which compiles successfully.
At LINE-2, the statement type == CCARD::SILVER compares between METAL type with CCARD
type, which are not type castable. Thus, it generates error.
At LINE-3, the statement type == TITANIUM compares between METAL type with int, which
are not type castable. Thus, it generates error.

4
Question 4
Consider the following code segment (in C++11). [MSQ, Marks 2]

#include <iostream>

template<typename T>
class ttype{
public:
ttype() = default;
ttype(T val) : val_(val){ }
ttype(const ttype& ) = default;
ttype& operator=(const ttype& ) = delete;
ttype(ttype&& ) = default;
ttype& operator=(ttype&& ) = delete;
private:
T val_;
};
int main(){
ttype<char> d1(’A’);
ttype<char> d2(d1); //LINE-1
ttype<char> d3;
d3 = d1; //LINE-2
ttype<char> d4 = std::move(d1); //LINE-3
ttype<char> d5;
d5 = std::move(d1); //LINE-4
return 0;
}

Which of the following line/s generate/s compilation error/s?

a) LINE-1

b) LINE-2

c) LINE-3

d) LINE-4

Answer: b), d)
Explanation:
Since assignment operator overload and move assignment operator overload are deleted, LINE-2
and LINE-4 both generates error.

5
Question 5
Consider the code segment (C++11) given below. [MCQ, Marks 2]

#include <iostream>

class customer{
public:
explicit customer() : customer(0) { } //LINE-1
explicit customer(const int ID) : customer(ID, defaultBalance) { } //LINE-2
explicit customer(const double balance) : customer(0, balance) { } //LINE-3
explicit customer(const int ID, const double balance)
: ID_{ID}, balance_{balance} { } //LINE-4
friend std::ostream& operator<<(std::ostream& os, const customer& st);
private:
int ID_ ;
double balance_ ;
static constexpr double defaultBalance = 1000.0;
};

std::ostream& operator<<(std::ostream& os, const customer& c){


os << "[" << c.ID_ << ", " << c.balance_ << "]" << ", ";
return os;
}

int main(){
customer c1;
customer c2(1011);
customer c3(2000.0); //LINE-5
customer c4(1012, 3000.0); //LINE-6
std::cout << c1 << c2 << c3 << c4;
return 0;
}

What will be the output/error?

a) [0, 0], [1011, 0], [2000, 0], [1012, 3000],

b) [0, 1000], [1011, 1000], [0, 2000], [1012, 3000],

c) compiler error at LINE-5: ambiguous call c3(2000.0)

d) compiler error at LINE-6: ambiguous call c4(1012, 3000.0)

Answer: b)
Expanation:
The statement at LINE-5 call the default constructor at LINE1, which delegates the call to the
parameterized constructor at LINE-2, which further delegates the call to the parameterized
constructor at LINE-4.

6
Question 6
Consider the code segment (C++11) given below. [MCQ, Marks 2]

#include <iostream>
#include <string>

class person {
public:
person(){}
explicit person(int ID) : ID_{ID} { }
protected:
int ID_ {0}; //LINE-1
std::string name_ {"unknown"}; //LINE-2
};

class customer: public person {


public:
explicit customer(double balance) : balance_{balance} { }
using person::person;
void print(){
std::cout << "[" << ID_ << ", " << name_ << ", " << balance_ << "]";
}
protected:
double balance_ {0.0}; //LINE-3
};

int main(){
customer c1(1011); //LINE-4
customer c2(30000.0); //LINE-5
c1.print();
c2.print();
return 0;
}

What will be the output/error?

a) [0, unknown, 1011][0, unknown, 30000]

b) [1011, unknown, 0][0, unknown, 30000]

c) Compiler error at LINE-1, LINE-2 and LINE-3: C++ does not allow in-class
initialization for the data members

d) Compiler error at LINE-4 and LINE-5: ambiguous calls

Answer: b)
Explanation:
The statement using person::person; in class customer allows customer to inherit the
default constructor from class person. Thus, the statement customer c1(1011); calls the
constructor from personinitializes the data member ID . Whereas, the statement customer
c2(30000.0); calls the constructor from class customer and initializes balance . Further-
more, C++11 allows in-class initialization so no error at LINE-1, LINE-2 and LINE-3. Thus,
b) is the correct option.

7
Question 7
Consider the code segment (C++14) given below. [MCQ, Marks 2]

#include <iostream>

template<typename T> T pi = T(22L)/7;


int main(){
pi<int> = 5;
//area of circle = pi * r * r
auto area1 = [](auto(r)) { return pi<decltype(r)> * r * r; }(10);
auto area2 = [](auto(r)) { return pi<double> * r * r; }(10);
auto area3 = [](auto(r)) { return pi<decltype(r)> * r * r; }(10.0);
auto area4 = [](auto(r)) { return pi<int> * r * r; }(10);
std::cout << area1 << ", " << area2 << ", " << area3 << ", " << area4;
return 0;
}

What will be the output?

a) 300, 314.286, 314.286, 300

b) 500, 314.286, 314.286, 500

c) 300, 314.286, 314.286, 500

d) 314.286, 314.286, 314.286, 500

Answer: b)
Explanation:
In the expression: [](auto(r)) { return pi<decltype(r)> * r * r; (10)}, the inferred
type of r is int. So, area1 = 500.
In the expression: [](auto(r)) { return pi<double> * r * r; }(10) , the pi<double>
is double(22L)/3. So, area2 = 314.286.
In the expression: [](auto(r)) { return pi<decltype(r)> * r * r; }(10.0) , the in-
ferred type of r is double. So, area3 = 314.286.
In the expression: [](auto(r)) { return pi<int> * r * r; }(10) , the pi<int> is 5. So,
the result is area4 = 500.

8
Question 8
Consider the code segment (C++11) given below. [MCQ, Marks 2]
#include <iostream>
#include <list>

int main(){
std::list<int> li {10, 20, 30, 40};
double sum = 0.0;
//start code-segment
auto add = [li, &sum](int d) {
double res = 0.0;
for(auto i : li){
sum += i;
res += (double)i/d;
}
return res;
};
//end code-segment
double r = add(5);
std::cout << sum << ", " << r;
return 0;
}
Identify the appropriate functor class implementation in place of the marked code segment(Portion
of the code marked by start and end) from the given options, such that the output of the pro-
gram remains the same that is the output is 100, 20.
a) struct add_closure {
std::list<int>& val_d;
double ref_d;
add_closure(std::list<int>& li, double sum) : val_d(li), ref_d(sum) { }
double operator()(int param) {
double res = 0.0;
for(auto i : val_d){
ref_d += i;
res += (double)i/param;
}
return res;
};
};
auto add = add_closure(li, sum);

b) struct add_closure {
std::list<int> val_d;
double ref_d;
add_closure(std::list<int> li, double& sum) : val_d(li), ref_d(sum) { }
double operator()(int param) {
double res = 0.0;
for(auto i : val_d){
ref_d += i;
res += (double)i/param;
}

9
return res;
};
};
auto add = add_closure(li, sum);

c) struct add_closure {
std::list<int> val_d;
double& ref_d;
add_closure(std::list<int> li, double& sum) : val_d(li), ref_d(sum) { }
double operator()(int param) const {
double res = 0.0;
for(auto i : val_d){
ref_d += i;
res += (double)i/param;
}
return res;
};
};
auto add = add_closure(li, sum);

d) struct add_closure {
std::list<int> val_d;
double& ref_d;
add_closure(std::list<int> li, double& sum) : val_d(li), ref_d(sum) { }
operator()(int param) const {
double res = 0.0;
for(auto i : val_d){
ref_d += i;
res += (double)i/param;
}
return res;
};
};
auto add = add_closure(li, sum);

Answer: c)
Explanation: For a λ-expression, the compiler creates a functor class with:

• data members:

– a value member each for each value capture


– a reference member each for each reference capture

• a constructor with the captured variables as parameters

– a value parameter each for each value capture


– a reference parameter each for each reference capture

• a public inline const function call operator() with the parameters of the lambda as
parameters, generated from the body of the lambda

• copy constructor, copy assignment operator, and destructor

10
Question 9
Consider the following code segment (in C++11). [MSQ, Marks 2]

#include <iostream>
#include <vector>

int main(){
int p = 1, s = 0;
std::vector<int> vec {1, 2, 3, 4};
______________________________________ { //LINE-1
for(auto& i : vec){
i *= m;
sum += i;
}
};
int sum = 0;
evalute(10, sum);
for(auto i : vec)
std::cout << i << ", ";
std::cout << sum;
return 0;
}

Identify the appropriate option(s) to fill in the blanks at LINE-1 such that the output becomes
10, 20, 30, 40, 100.

a) auto evalute = [](int m, int& sum)

b) auto evalute = [&vec](int m, int& sum)

c) auto evalute = [=](int m, int& sum)

d) auto evalute = [&](int m, int& sum)

Answer: b), d)
Explanation:
Since the variable vec is modified within the lambda function, it needs to be captured by
reference. Therefore, both options b) and d) are correct.

11
Programming Questions

Question 1
Consider the following program that implements a recursive lambda function to find out the
nm , where n, m ≥ 1.

• Fill in the blank at LINE-1 to declare the signature of recPow as std::function.

• Fill the blank at LINE-2 to complete the definition of lambda function recPow.

• Fill the blank at LINE-3 to complete the definition of lambda expression print, which
calls recPow.

The program must satisfy the sample input and output. Marks: 3

#include <iostream>
#include <functional>

int main(){
___________________________________; //LINE-1
recPow = ______________________________ { //LINE-2
return m == 1 ? n : n * recPow(n, m - 1);
};
auto print = ______________________ { //LINE-3
std::cout << recPow(n, m);
};
int n, m;
std::cin >> n >> m;
print(n, m);
return 0;
}

Public 1
Input: 2 5
Output: 32

Public 2
Input: 4 3
Output: 64

Private
Input: 10 3
Output: 1000

Answer:
LINE-1: std::function<int(int, int)> recPow
LINE-2: [&recPow](int n, int m) -> int
LINE-3: [&recPow](int n, int m)
Explanation:
At LINE-1, we can use std::function to declare the signature of RecMin as:
std::function<int(std::vector<int>, int)> RecMin

12
At LINE-2 to complete the definition of lambda function RecMin is as follows:

recPow = [&recPow](int n, int m) -> int { //LINE-2


return m == 1 ? n : n * recPow(n, m - 1);
};

At LINE-3 to complete the definition of lambda expression print is as follows:

auto print = [&recPow](int n, int m) {


std::cout << recPow(n, m);
};

13
Question 2
Consider the following program (in C++11).

• Fill in the blanks at LINE-1 and LINE-3 with appropriate template definitions.

• Fill in the blanks at LINE-2 and LINE-4 with appropriate parameters for getmin function.

The program must satisfy the sample input and output. Marks: 3

#include <iostream>

___________________________________ //LINE-1
double getmin(________){ return num; } //LINE-2

___________________________________ //LINE-3
double getmin(_____________________){ //LINE-4
return num <= getmin(nums...) ? num : getmin(nums...); //LINE-4
}

int main(){
int a, b, c;
double d, e, f, g;
std::cin >> a >> b >> c;
std::cin >> d >> e >> f >> g;
std::cout << getmin(a, b, c) << " ";
std::cout << getmin(d, e, f, g) << " ";
std::cout << getmin(a, b, c, d, e, f, g) << " ";
return 0;
}

Public 1
Input:
3 1 5
3.4 5.7 1.2 8.9
Output: 1 1.2 1

Public 2
Input:
4 3 2
9.8 1.2 3.4 .9
Output: 2 0.9 0.9

Private
Input:
7 0 9
1 0.0 2.3 8.1
Output: 0 0 0

Answer:
LINE-1: template <typename T>
or

14
LINE-1: template <class T>
LINE-2: T num
LINE-3: template <typename T, typename... Tail>
or
LINE-3: template <class T, class... Tail>
LINE-4: T num, Tail... nums
Explanation:
At LINE-1, the definition of the simple template is:
template <typename T>
, and at LINE-3 the parameter of the function findMax are:
T num
At LINE-3, the definition of the veriadic template is:
template <typename T, typename... Tail>
, and at LINE-4 the parameters of the function findMax are:
T num, Tail... nums

15
Question 3
Consider the program below (in C++11).

• Fill in the blank at LINE-1 with appropriate template declaration.

• Fill in the blank at LINE-2 with an appropriate parameter for function makePayment.

• Fill in the blank at LINE-3 to complete the return statement.

The program must satisfy the given test cases. Marks: 3

#include <iostream>
class payment{
public:
virtual void pay() = 0;
};

class upi_payment : public payment {


public:
upi_payment(const int& upi_num) : upi_num_{upi_num}{
std::cout << "lvalue" << " ";
}
upi_payment(int&& upi_num) : upi_num_{upi_num}{
std::cout << "rvalue" << " ";
}
void pay(){ std::cout << upi_num_ << " "; }
private:
int upi_num_;
};

class bank_transfer : public payment {


public:
bank_transfer(const int& acc_no) : acc_no_(acc_no){
std::cout << "lvalue" << " ";
}
bank_transfer(int&& acc_no) : acc_no_(acc_no){
std::cout << "rvalue" << " ";
}
void pay(){ std::cout << acc_no_ << " "; }
private:
int acc_no_;
};

____________________________________ //LINE-1
T1 makePayment(________){ //LINE-2
return ___________________________; //LINE-3
}
int main() {
int a, b;
std::cin >> a >> b;

auto p1 = makePayment<upi_payment>(a);
auto p2 = makePayment<upi_payment>(std::move(a));

16
auto p3 = makePayment<bank_transfer>(b);
auto p4 = makePayment<bank_transfer>(std::move(b));
std::cout << std::endl;
p1.pay();
p2.pay();
p3.pay();
p4.pay();
return 0;
}

Public 1
Input: 10 20
Output:
lvalue rvalue lvalue rvalue
10 10 20 20

Public 2
Input: 5 3
Output:
lvalue rvalue lvalue rvalue
5 5 3 3

Private
Input: 1 2
Output:
lvalue rvalue lvalue rvalue
1 1 2 2

Answer:
LINE-1: template<typename T1, typename T2>
or
LINE-1: template<class T1, class T2>
LINE-2: T2&& val
LINE-3: T1(std::forward<T2>(val))
Explanation:
This code is a typical example of factory method. Since the function return type and the
parameters both are template parameter type, at LINE-1 the template must be declared as:
template<typename T1, typename T2>
or
template<class T1, class T2>
The parameter for makePayment must be universal reference type which can be declared as:
LINE-2: T2&& valm
Depending on the instantiation of parameter type T1 the function makePayment return an
object of upi payment or bank transfer type, which can be done as:
T1(std::forward<T2>(val))

17

You might also like