Search code examples
c++oopdesign-patterns

Construct two classes that has attributes and can use methods of each other


I'd like to know is it possible that two classes has attributes and can use methods of each other. For example, there're a class STUDENT and a class COURSE, a STUDENT have a list of joined courses and a COURSE have list of participants(students). I tried this:

in STUDENT.h

#include <iostream>
#include <vector>
// #include "COURSE.h"

class COURSE;

class STUDENT {
    string name;
    std::vector<COURSE*> listCourses;
public:
    STUDENT(){};

    addCourse(COURSE* &course){
        listCourses.push_back(course);
        course.addStudent(this);
    }
    
    string getName(){
       return this->name;
    }
    
    void showCourses(){
       for(COURSE* course : listCourses)
          std::cout << course->getName() << std::endl;
    }
};

in COURSE.h

#include <iostream>
#include <vector>
// #include "STUDENT.h"

class STUDENT;

class COURSE {
    string name;
    std::vector<STUDENT*> listStudents;
public:
    COURSE(){}

    addStudent(STUDENT* &student){
        listStudents.push_back(student);
        student.addCourse(this);
    }
      
    string getName(){
       return this->name;
    }
    
    void showStudent(){
       for(STUDENT* student : listCourses)
          std::cout << student->getName() << std::endl;
    }

};

If I include two classes each other, it said errors. If I just include one, just one class worked, other class has problem.

Can anyone help me to fix it and I wonder that is it necessary to use some design patterns or data structures to solve this. Thank you


Solution

  • Yes, what you are attempting is possible, but not in the way you are attempting it. You need to separate your method declarations and definitions.

    Also, you have a flaw in your add... methods that will lead to endless recursion as soon as a Student is added to a Course or vice versa. You need to detect when the two are already linked together so that you can avoid the loop.

    Try something more like this:

    Student.h

    #ifndef StudentH
    #define StudentH
    
    #include <vector>
    #include <string>
    
    class Course;
    
    class Student {
        std::string name;
        std::vector<Course*> listCourses;
    public:
        Student() = default;
        ~Student();
    
        std::string getName() const;
    
        void addCourse(Course* course);
        void removeCourse(Course* course);
        void showCourses() const;
    };
    
    #endif
    

    Student.cpp

    #include "Student.h"
    #include "Course.h"
    
    #include <iostream>
    #include <algorithm>
    
    Student::~Student() {
        for(Course* course : listCourses) {
            course->removeStudent(this);
        }
    }
    
    std::string Student::getName() const {
        return name;
    }
    
    void Student::addCourse(Course* course) {
        if (std::find(listCourses.begin(), listCourses.end(), course) == listCourses.end()) {
            listCourses.push_back(course);
            course->addStudent(this);
        }
    }
        
    void Student::removeCourse(Course* course) {
        auto iter = std::find(listCourses.begin(), listCourses.end(), course);
        if (iter != listCourses.end()) {
            listCourses.erase(iter);
            course->removeStudent(this);
        }
    }
        
    void Student::showCourses() const {
        for(Course* course : listCourses) {
            std::cout << course->getName() << std::endl;
        }
    }
    

    Course.h

    #ifndef CourseH
    #define CourseH
    
    #include <vector>
    #include <string>
    
    class Student;
    
    class Course {
        std::string name;
        std::vector<Student*> listStudents;
    public:
        Course() = default;
        ~Course();
    
        std::string getName() const;
    
        void addStudent(Student* student);
        void removeStudent(Student* student);
        void showStudents() const;
    };
    
    #endif
    

    Course.cpp

    #include "Course.h"
    #include "Student.h"
    
    #include <iostream>
    #include <algorithm>
    
    Course::~Course() {
        for(Student* student : listStudents) {
            student->removeCourse(this);
        }
    }
    
    std::string Course::getName() const {
        return name;
    }
    
    void Course::addStudent(Student* student) {
        if (std::find(listStudents.begin(), listStudents.end(), student) == listStudents.end()) {
            listStudents.push_back(student);
            student->addCourse(this);
        }
    }
          
    void Course::removeStudent(Student* student) {
        auto iter = std::find(listStudents.begin(), listStudents.end(), student);
        if (iter != listStudents.end()) {
            listStudents.erase(iter);
            student->removeCourse(this);
        }
    }
        
    void Course::showStudents() const {
        for(Student* student : listStudents) {
            std::cout << student->getName() << std::endl;
        }
    }