You can go with two big global-ish multimaps as you suggest, or you could maintain the information locally in the project and employee data structures. Have the Project class contain a vector (or set) of pointers to Employee, and the Employee class contain a vector/set of pointers to Project, plus a function that associates an Employee to a Project by pushing a pointer to each onto the vector of the other. Then given either object, you can get the collection of objects of the other type that are associated with it. Something like:
(in Employee.h):
class Project; // Forward declare project
class Employee {
public:
AddProject(Project *proj);
vector<Project *> projects();
size_t num_projects() {return projects_.size();}
Project *project(size_t i) {return projects_[i];}
private:
vector<Project *> projects_;
};
and similarly for Project.h.
Either approach can work; the local approach is the way you would typically do it in a language like C where you don't have multimap available. You can also use indices or IDs in place of pointers. One advantage of the local approach is that more of the work you need to do with Projects and Employees can become local behavior of the Project/Employee classes, implemented with methods of those classes, and unit tested separately from the rest of the system. That doesn't work with the multimap approach, since the individual classes know nothing of the multimaps.
The difference isn't so apparent here, where you only have the two classes, but I've seen cases where lots of these kinds of relationships were represented with large global-ish data structures that were part of a huge monster class, and unit testing became almost impossible (since you needed to set up so many data structures in the monster class to get anything done).