I don't think that
std::map <std::string,std::string> exam_taken;
and
void take_exam(std::string student_no) { exam_taken[student_no] = exam_number; };
belong in exam class.
An exam doesn't care if it was taken or not. Instead, a school does.
So, my suggestion is to add another class called school that will hold lists of students,teachers and exams. It'll also implement all the functions that interact with different objects. 'take_exam' is one of these functions. I think void teacher::add_course (std::string course) could also be moved into a school class
Remarks for a new code version:
What bothers me is the fact that student has no relation to a course at all. So you may ask the student to take an exam in a course he/she didn't study at all.
Below are my suggestions:
Course class
holds list of registered users
- Register(student) method
- GiveExam(exam) method - calls each registered student TakeExam method Teacher class should expose
Teacher class should expose
- Register(course) method,
- SetExam(course, exam)
School class should orchestrate the rest of the classes and do things like initialization (like you already doing) and assignment of teachers to courses and exams to courses (though Teacher class)