Many-to-Many Relationship Between Objects

Viewed 110

Here is the code In Movie.hpp

#ifndef MOVIE_H
#define  MOVIE_H

class Movie
{
  private:
    std::string title;
  public:
    std::string getTitle() const {return this->title;}  // const added 
    void setTitle(std::string newTitle){this->title = newTitle;}
};


#endif

In Actor.hpp

#ifndef ACTOR_H
#define  ACTOR_H

#include "Person.hpp"
#include "Movie.hpp"

class Actor: public Person
{
  private:
    std::vector<Movie> movieList;
  public:
    void addMovie(Movie newMovie){this->movieList.push_back(newMovie);}
    void printMovies()
    {
      for(Movie movie: this->movieList)
      {
        std::cout << movie.getTitle() << '\n';
      }
    }
};

#endif

In Main.cpp I'm doing something like

Movie movie1, movie2, movie3; 
  Actor actor1, actor2;

  movie1.setTitle("Transformers");
  movie2.setTitle("Interstellar");
  movie3.setTitle("The Matrix");

  actor1.setName("Brad");
  actor1.setAge(57);
  actor1.addMovie(movie1); //here
  actor1.addMovie(movie2);

  actor2.setName("Justin");
  actor2.setAge(30);
  actor2.addMovie(movie3);

I have been instructed that I'm not following many-to-many relationship. In other words, if actor1 and actor2 have a connection with the same movie, they should share the same 'Movie' object. In my case, they have different movie objects. The proper way is to store pointers to Movie inside Actor:

std::vector<Movie*> movieList;

(collection of pointers, not of objects)

and inside Movie:

std::vector<Actor*> actorList;

Another proper way, I prefer this one, is to add a separate class

class Role {
private:
   Actor* actor;
   Movie* movie;
};

and store collection of such objects inside Movie and Actor, here values (not pointers) are OK

std::vector<Role> movieList; //inside Actor

std::vector<Role> actorList; //inside Movie

I have the idea how to solve above problem but I'm unable to make the changes in above code while using pointer. Can someone please help me out what changes will be there when I use pointers ?

2 Answers

You can use vectors and smart pointers. I don't know which version of c++ you use, but you can use std::shared_ptr<Movie> and std::shared_ptr<Actor>. And each movie and actor will have his own vector of shared pointers. Such smart pointers are available from c++ 11. So if you use version of c++ that is before c++ 11, you can use boost library, which include these smart pointers: boost::shared_ptr<Movie> and boost::shared_ptr<Actor>

My suggestion would be to have a master-list of movies and actors, each stored as a vector of std::shared_ptr.

Then in the Actor and Movie objects you can have a vectors (also) of std::shared_ptr of each other.

So first the master lists:

std::vector<std::shared_ptr<Movie>> master_movies;
std::vector<std::shared_ptr<Actor>> master_actors;

And the classes:

// Forward declaration
class Movie;

class Actor
{
    // ...

public:
    void addMovie(std::shared_ptr<Movie> movie)
    {
        movies.emplace_back(movie);
    }

private:
    // Movies that the actor has been in
    std::vector<std::shared_ptr<Movie>> movies;
};

class Movie
{
    // ...

public:
    void addActor(std::shared_ptr<Actor> actor)
    {
        actors.emplace_back(actor);
    }

private:
    // Actors in this movie
    std::vector<std::shared_ptr<Actor>> actors;
};

Always create the actors and movies in the master lists, and add movies to actors from the movie master list, and add actors to movies from the actor master list:

auto fear = std::make_shared<Movie>();
fear->setTitle("Fear and loathing in Las Vegas");
master_movies.emplace_back(fear);

auto depp = std::make_shared<Actor>();
depp->setName("Johnny Depp");
master_actors.emplace_back(depp);

depp->addMovie(fear);
fear->addActor(depp);
Related