1. Virtual destructor and example problems
1.1. Virtual destructor
1.1.1. Example 1 – Why and when we need virtual destructor?
oop_av121a_en.cpp
#include <iostream>
using namespace std;
class Base {
public:
Base() { cout << "Constructor of Base\n";}
// this is the destructor
~Base() { cout << "Destructor of Base\n";}
};
class Derived : public Base
{
public:
Derived() { cout << "Constructor of Derived\n"; }
~Derived() { cout << "Destructor of Derived\n"; }
};
int main() {
Base *basePointer = new Derived();
delete basePointer;
}
Constructor of Base Constructor of Derived Destructor of Base
oop_av121b_en.cpp
#include <iostream>
using namespace std;
class Base {
public:
Base() { cout << "Constructor of Base\n";}
// this is the destructor
virtual ~Base() { cout << "Destructor of Base\n";}
};
class Derived : public Base
{
public:
Derived() { cout << "Constructor of Derived\n"; }
~Derived() { cout << "Destructor of Derived\n"; }
};
int main() {
Base *basePointer = new Derived();
delete basePointer;
}
Constructor of Base Constructor of Derived Destructor of Derived Destructor of Base
1.2. Second partial exam 2015/2016
1.2.1. Problem 1
Define a class Goal
that keeps information for:
-
the goal scorer (dynamically allocated array of characters),
-
time (the minute) of the goal scoring event (integer),
-
name of the team that scored the goal (char array max 50).
For this class implement:
-
constructor with all three arguments
-
operator
<<
for printing onostream
an object of classGoal
(print the minute and the name) -
operator
++
(postfix) notation for incrementing the minute for one, -
operator
--
(prefix) notation for decrementing the minute for one.
Also create a class Game
that keeps dynamically allocated array of objects from the class Goal
and the names of the teams that play that game (two char arrays of 50). For this class implement:
-
constructor with two arguments the names of the teams that play the game
-
the unary operator
+=
for adding an object of classGoal
in the array of objects. If the name of the object from the classGoal
is not equal to the one of the names of the teams that play the game then throw an exception of typeInvalidTeamName
. Handling the exception should be in the appropriate place in the main function, by printing the messageInvalid team name: [the_name]
-
operator
<<
for printing on theostream
the teams that play the game and all the scorers.
oop_av122_en.cpp
#include <iostream>
#include <cstring>
using namespace std;
class InvalidTeamName : exception {
char msg[100];
public:
InvalidTeamName(const char* name) {
strcpy(msg, name);
}
const char* what() {
return msg;
}
};
class Goal {
private:
char* name;
int minute;
char team[50];
void copy(const Goal &g) {
name = new char[strlen(g.name)];
strcpy(name, g.name);
minute = g.minute;
strcpy(team, g.team);
}
public:
Goal() {
name = NULL;
}
Goal(const char* n, int m, const char* t) {
name = new char[strlen(n)];
strcpy(name, n);
minute = m;
strcpy(team, t);
}
Goal(const Goal &g) {
copy(g);
}
Goal& operator=(const Goal& g) {
if(&g == this) return *this;
delete [] name;
copy(g);
return *this;
}
friend ostream& operator<<(ostream& out, const Goal& g) {
out << g.minute << " " << g.name;
return out;
}
Goal operator++(int) {
Goal g = *this;
++minute;
return g;
}
Goal& operator--() {
--minute;
return *this;
}
char* getTeam() {
return team;
}
};
class Game {
private:
Goal* goals;
char teamHome[50];
char teamGuest[50];
int n;
void copy(const Game& game) {
goals = new Goal[game.n];
n = game.n;
for(int i = 0; i < n; ++i) {
goals[i] = game.goals[i];
}
strcpy(teamHome, game.teamHome);
strcpy(teamGuest, game.teamGuest);
}
public:
Game(const char* t1, const char* t2) {
goals = NULL;
n = 0;
strcpy(teamHome, t1);
strcpy(teamGuest, t2);
}
Game(const Game& game) {
copy(game);
}
Game& operator=(const Game& game) {
if(this == &game) return *this;
delete [] goals;
copy(game);
return *this;
}
Game& operator+=(Goal &g) {
if(strcmp(g.getTeam(), teamHome) != 0&&strcmp(g.getTeam(), teamGuest)) {
throw InvalidTeamName(g.getTeam());
}
Goal* temp = goals;
goals = new Goal[n + 1];
for(int i = 0; i < n; ++i) {
goals[i] = temp[i];
}
delete [] temp;
goals[n] = g;
++n;
return *this;
}
friend ostream& operator<<(ostream &out, const Game &n) {
out << n.teamHome << " - " << n.teamGuest << endl;
for(int i = 0; i < n.n; ++i) {
cout << n.goals[i] << endl;
}
return out;
}
};
int main() {
char team1[50];
char team2[50];
cin >> team1;
cin >> team2;
Game n(team1, team2);
int x;
cin >> x;
char player[100];
int m;
for(int i = 0; i < x; ++i) {
cin >> player;
cin >> m;
cin >> team1;
Goal g(player, m, team1);
try {
n += g;
} catch(InvalidTeamName &e) {
cout << "Invalid team name: " << e.what() << endl;
}
}
cout << n << endl;
return 0;
}
1.3. Problem 2
Implement class for Ticket
that keeps info for ID of the ticket as an array of 50 characters and a length of the ID (integer that is not larger than 50).
From this class derive two classes for tickets DigitsTicket`and `CharTicket
that should implement the following methods:
-
constructor with one argument N the length of the ID that generates a random ID with the given length
-
for the class
DigitTicket
generates N random digits and fills the ID with them. -
for the class
CharTicket
generates N random characters (A-Z) and fills the ID with them. -
you should use the external functions for generating random digit
randomDigit
and random charrandomChar
-
bool validate()
to validate the ticket -
for the class
DigitTicket
the ID is valid if the sum of the digits is a number divisible with 7 -
for the class
CharTicket
the ID is valid if the sum of the ASCII codes is a number divisible with 3.
Override the operators ==
and !=
for comparing two tickets of any kind by their ID. Two tickets are equal if they have the same ID.
Implement an external function int valid(Ticket **tickets, int n)
that for an array of pointers of the class Ticket
and the length of the array, will return how many of the tickets are valid.
Implement an external function int unique(Ticket **tickets, int n)
that for an array of pointers of the class Ticket
and the length of the array, will return how many of the tickets are unique (does not have duplicate in the rest of the array). If there is at least one ticket with the same ID with given ticket, that ticket is NOT unique.
oop_av123_en.cpp
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
char randomDigit() {
return '0' + rand() % 10;
}
char randomChar() {
return 'A' + rand() % 26;
}
class Ticket {
protected:
char id[50];
int len;
public:
virtual bool validate() const = 0;
friend ostream& operator<<(ostream& out, const Ticket &t) {
for(int i = 0; i < t.len; ++i) {
out << t.id[i];
}
return out;
}
bool operator==(const Ticket& t) {
if(len != t.len) return false;
for(int i = 0; i < t.len; ++i) {
if(id[i] != t.id[i]) return false;
}
return true;
}
};
class DigitTicket : public Ticket {
public:
DigitTicket(int n) {
len = n;
for(int i = 0; i < n; ++i) {
id[i] = randomDigit();
}
}
bool validate() const {
int sum = 0;
for(int i = 0; i < len; ++i) {
sum += id[i] - '0';
}
return sum % 7 == 0;
}
};
class CharTicket : public Ticket {
public:
CharTicket(int n) {
len = n;
for(int i = 0; i < n; ++i) {
id[i] = randomChar();
}
}
bool validate() const {
int sum = 0;
for(int i = 0; i < len; ++i) {
sum += id[i];
}
return sum % 3 == 0;
}
};
int valid(Ticket** t, int n) {
int valid = 0;
for(int i = 0; i < n; ++i) {
if(t[i]->validate()){
++valid;
}
}
return valid;
}
int unique(Ticket **t, int n) {
int duplicates = 0;
for(int i = 0; i < n - 1; ++i) {
for(int j = i + 1; j < n; ++j) {
if(*t[i] == *t[j]&&i != j) {
++duplicates;
}
}
}
return n - duplicates;
}
int main() {
int seed;
cin >> seed;
srand (seed);
int n;
cin >> n;
Ticket **t = new Ticket*[n];
cout << "===== ALL TICKETS (" << n << ") =====" << endl;
for(int i = 0; i < n; ++i) {
int x;
cin >> x;
if(i % 2 == 0) {
t[i] = new DigitTicket(x);
} else {
t[i] = new CharTicket(x);
}
cout << *t[i] << endl;
}
cout << "===== VALID =====" << endl;
cout << valid(t, n) << endl;
cout << "===== UNIQUE =====" << endl;
cout << unique(t, n) << endl;
for(int i = 0; i < n; ++i) {
delete t[i];
}
delete [] t;
return 0;
}