A console application that manages students, courses and enrollments. It stores the data in memory, writes it to a file and reads it back, and can fetch generated test students from a remote server over TCP.
Written for the Advanced Programming Techniques course. The point of the exercise was ownership and polymorphism in modern C++, not the domain itself.
StudentDb
├── std::map<int, Student> m_students
└── std::map<int, std::unique_ptr<const Course>> m_courses
Student ──has──> Address
└─has──> std::list<Enrollment> ──points to──> const Course*
Course (abstract)
├── WeeklyCourse day of week, start and end time
└── BlockCourse start and end date, start and end time
Course is abstract and the database owns the courses through
std::unique_ptr<const Course>. Students hold enrollments that only point at a course,
they never own it, so a course exists exactly once and cannot be deleted while the
database is alive. That is the main design decision in this program.
Ownership. Courses are unique and non copyable, so addCourse takes a
std::unique_ptr<Course> by value and moves it into the map. addStudent takes
Student&& for the same reason. An Enrollment stores a raw const Course*, which is
correct here because the database outlives every enrollment and the pointer is
non owning.
Polymorphic serialization. Course::write is pure virtual. Each subclass writes a
single type character first, W or B, then calls the protected writeBase for the
common fields. Reading is the mirror image: the static factory Course::read looks at
the first character and constructs the right subclass, returning a unique_ptr<Course>.
This keeps the file format readable and puts the type decision in one place.
The major is stored as a char. Course keeps the major internally as one character
and holds two static maps for the conversion in both directions. The getter returns the
full string, so the compact storage is not visible from the outside.
Validation in the constructor. An empty title, an unknown major or zero credit
points all throw std::invalid_argument. A Course object cannot exist in an invalid
state.
Remote test data. generateTestStudents() opens a
boost::asio::ip::tcp::iostream to www.hhs.users.h-da.cloud:4242, sends generate,
parses each JSON line with boost::json, builds Student objects from the fields, and
sends quit before closing. This is how the database gets filled with a few hundred
records without typing them in.
[number of courses]
[course lines]
[number of students]
[student lines]
[number of enrollments]
[enrollment lines]
Fields are separated by ;. Loading clears the database first and sets the next
matriculation number to the highest one read plus one.
1. Add new course 6. Update student
2. Print course list 7. Save database
3. Add new student 8. Load database
4. Print student 9. Generate test students
5. Search student 10. Quit
SimpleUI holds the whole menu and all input validation, so StudentDb never touches
std::cin and can be used without the console.
| File | Contents |
|---|---|
src/Course.*, src/WeeklyCourse.*, src/BlockCourse.* |
Abstract course and the two concrete types, with the read and write pair |
src/Student.*, src/Address.*, src/Enrollment.* |
Student record, address, and the enrollment that links a student to a course |
src/StudentDb.* |
Storage, name search, enrollment handling, file format, remote test data |
src/SimpleUI.* |
Console menu and input validation |
src/main.cpp |
Entry point |
Needs a C++14 compiler and Boost, tested with Boost 1.83 and 1.90.
g++ -std=c++14 src/*.cpp -o studentdb -lboost_json
The project was developed in Eclipse CDT, so the workspace files are not in this repository.
Advanced Programming Techniques, M.Sc. Electrical Engineering and Information Technology, Hochschule Darmstadt, winter semester 2025/26.