Object-Oriented Programming in C++
2022-23 Coursework To be done individually Don’t “help” others – they can help themselves by studying the relevant material
Setting Up
First, make sure you have a proper (command line-based) environment to develop and test your code. Use whichever IDE you want but your code MUST work with g++ version >=12.
To test that everything works OK, copy-paste the following highlighted text in a Linux/ WSL+Ubuntu/Mac terminal:
cd ; mkdir tst; cd tst
cat > Makefile << EOF_Makefile
CXXFLAGS=-std=c++20 -pedantic -Wall -Wpointer-arith -Wwrite-strings
CXXFLAGS+=-Wcast-qual -Wcast-align -Wformat-security
CXXFLAGS+=-Wformat-nonliteral -Wmissing-format-attribute
CXXFLAGS+=-Winline -funsigned-char
CC=\$(CXX)
EOF_Makefile
cat > hello.cc << EOF_Hello
#include <iostream>
using namespace std;
#define X(token) #token
int main() {
cout << X(Hello) << char(32) << X(World) << char(33) << endl;
return 0;
}
EOF_Hello
make hello && ./hello
Does it print "Hello World!"? With no warnings/errors? Congratulations, you’re good to go! If the above doesn’t work, contact me ASAP!!! (and copy-paste the output of g++ --version – your compiler may be called g++-12 instead, so also g++-12 --version) Quick solution for Linux/MacOS – COPY-PASTE (DON’T TYPE!) THE FOLLOWING: On both: 1) Get brew (one line!!!): /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" On Linux only: 1.5) Add brew to PATH (for default installation!!!): export PATH="${PATH}:/home/linuxbrew/.linuxbrew/bin" echo 'export PATH="${PATH}:/home/linuxbrew/.linuxbrew/bin"' >> ~/.profile On both: 2) Install gcc@12: brew install gcc On both: 3) Make sure g++-12 is the default (now & in the future): export CXX=g++-12 echo export CXX=g++-12 >> ~/.profile
Use the C++ compiler as the C compiler to avoid linking errors. export CC=${CXX} echo export 'CC=${CXX}' >> ~/.profile Debugging Tips: • Are you using a Mac? The g++ compiler that comes with MacOS isn't really g++, it's clang++ (try g++ --version) – you need to install gcc from Brew as above and then use g++-12 instead of g++ • Are you using a Windows terminal? Use WSL+Ubuntu [2] (or Linux). • Are you using a shell that isn’t Bash? Do "echo $SHELL" to see which shell you use (mine is /bin/bash) and run "bash" to use the Bash shell in just this terminal. • Did you try to type the above code yourself? Copy-paste it.
Your code should compile with no warnings using the Makefile file defined above (i.e., that set of compiler flags).
It’s source code files that you should submit (q1.cc, q2.cc, …), not executables.
Questions
Session 2 – Classes in C++ & Session 4 – Genericity, Containers
-
Consider the following code. Fix the yellow parts, without modifying the parts in gray, so that the code compiles and runs correctly.
#include <iostream> using namespace std; // File: q1.cc class person { int age; public: person(int a = 10) : age(a) {} int get_age() const; void set_age(int a); }; /* Your code here */ // // // int main() { person p1; p1.set_age(25); cout << p1.get_age() << endl; // should print 25 return 0; }
-
Consider this slightly modified version of the person class – fix it by adding code in the yellow parts.
#include <iostream> using namespace std; // File: q2.cc class person { int age; public: // person(int a) : age(a) {} int get_age() const; void set_age(int a); }; // // // int main() { person p1; p1.set_age(25); cout << p1.get_age() << endl; // should print 25 return 0; }
-
One more person class variant – this time a generic class. Fix the yellow parts, without modifying the parts in gray, so that the code compiles and runs correctly.
#include <iostream> using namespace std; // File: q3.cc template <typename T> class person { // NOT class person<T> !!! T age; public: person(T a = 10) : age(a) {} T get_age() const; void set_age(T a); }; /* Your code here */ // // // int main() { person<unsigned char> p1; p1.set_age(25); cout << (int) p1.get_age() << endl; // should print 25 return 0; }
-
Now consider this final person class variant. Complete the main so that it prints 25 after having printed 10, without adding more methods to class person or changing the visibility of its members.
#include <iostream> using namespace std; // File: q4.cc class person { int age; public: person(int a = 10) : age(a) {} int get_age() const; }; /* Your code here */ int main() { person p1; cout << p1.get_age() << endl; // should print 10 /* Your code here */ cout << p1.get_age() << endl; // should print 25 return 0; }
-
Consider the following use of class my_array_class. Fix the code in the class so that the grayed-out code compiles and runs correctly. Note: you should not modify any of the code in gray.
#include <iostream> using namespace std; // File: q5.cc class my_array_class { size_t len = 3; int *a = new int [3]; public: my_array_class() { a[0] = 1; a[1] = 2; a[2] = 3; } my_array_class(size_t ln, const int *o) : len(ln), a(new int [ln]) { for (size_t n=0; n<ln; ++n) a[n] = o[n]; } ~my_array_class() { delete[] a; } size_t get_length() { return len; } int get(size_t n) {return a[n];} int set(size_t n, int v) { int tmp = a[n]; a[n] = v; return tmp; } };
void foo( const my_array_class & a2, size_t i ) { if (i < a2.get_length()) std::cout << a2.get(i) << std::endl; }
int main() { int zero12[] = {13, 1, 2}; my_array_class a1(3, zero12); foo(a1, 0); // should print 13 return 0; }
### Session 3 – Overloading
6. Extend the code in the class my_array_over below so that the grayed-out code compiles and runs correctly. (Hint: compare the grayed-out code here with Q5’s.)
include
using namespace std; // File: q6.cc class my_array_over { size_t len = 1; int a = new int [1]; public: my_array_over() { a[0] = 0; } my_array_over(size_t ln, const int o) : len(ln), a(new int [ln]) { for (size_t n=0; n<ln; ++n) a[n] = o[n]; } ~my_array_over() { delete[] a; } / Put your code here / }; void foo( const my_array_over & a2, size_t i ) { if (i < a2.get_length()) std::cout << a2[i] << std::endl; } int main() { int zero12[] = {23, 1, 2}; my_array_over a1(3, zero12); a1.set(0, 13); foo(a1,0); // should print 13 return 0; }
7. Now do the same as in Q6 for the following code.
include
using namespace std; // File: q7.cc class my_array_over2 { size_t len = 1; int a = new int [1]; public: my_array_over2() { a[0] = 0; } my_array_over2(size_t ln, const int o) : len(ln), a(new int [ln]) { for (size_t n=0; n<ln; ++n) a[n] = o[n]; } ~my_array_over2() { delete[] a; } / Put your code here / };
void foo( const my_array_over2 & a2, size_t i ) { if (i < a2.get_length()) std::cout << a2[i] << std::endl; }
int main() { int zero12[] = {13, 1, 2}; my_array_over2 a1(3, zero12); a1[1] = 14; / EXTRA LINE!!! / foo(a1,1); // should print 14 return 0; }
8. Consider the following class used for holding 2-dimensional (mathematical) vectors. Overload the output ([6]) and input ([12]) operators so that you can print and read objects of this class.
include
include
include
include
include
using namespace std; // File: q8.cc
class m2dvector {
vector
int main() {
try {
vector
### "Session 4 – Genericity, Containers" & "Session 5 – Pointers and Arrays Iterators"
9. Consider the following code – complete it (in the yellow area) so that it compiles and runs.
[12]
#include <iostream>
#include <map>
#include <atring>
#include <algorithm>
using namespace std; // File: q9.cc
template <typename X, typename Y>
class class1 {
map<X, Y> map1;
public:
class1(map <X, Y> some_map);
const map <X, Y> & get_data() const;
};
/* a) Put your code here to get it to compile */
int main() {
map<int, float> mi2f = { {1, 11}, {2, 12}, {3, 13}};
class1<int, float> c1(mi2f);
const map<int, float> & c1dt = c1.get_data();
/* b) Put your code here to print the elements of c1dt. */
return 0;
}
## Part II – A simple phonebook app
The following questions consider the case where we need to develop a simple phone book.
10. Develop a class person that offers get/set_name() methods (no need to split into forename/surname – a single name will do).
11. Develop two classes – person_with_phone and person_with_email that each inherits from person, with appropriate get/set_phone() and get/set_email() methods.
12. Develop a class person_with_phone_email that inherits from both person_with_phone and from person_with_email.
[10]
13. Appropriately overload operator<< so that you can print any type of person. The format to be used is:
"<person N " name[" T " telephone]?[" E " email]? " >"
The notation "[a]?" means that "a" may be present or absent. The output ends with a space (" ") followed by the greater than (">") symbol.
Examples (use them all):