使用指针更改代码以实现多对多关系

Change the Code Using Pointers to Achieve Many-to-Many Relationship

我在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

在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

在主可执行文件中Main.cpp

 Movie movie1, movie2, movie3;        
  Comment comment1, comment2, comment3;
  Viewer viewer1, viewer2;
  Actor actor1, actor2;
  Celebrity celebrity1;

  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(movie1);   // added
  actor2.addMovie(movie3);

现在,我被告知我的代码没有遵循多对多关系。换句话说,如果 actor1 和 actor2 与同一部电影有联系,他们应该共享同一个 'Movie' 对象。在我的例子中,他们有不同的电影对象。 正确的方法是在 Actor 中存储指向 Movie 的指针:

std::vector<Movie*> movieList;

(指针的集合,不是对象的集合)

和电影里面:

std::vector<Actor*> actorList;

另一个正确的方法,我更喜欢这个,是添加一个单独的 class

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

并在 Movie 和 Actor 中存储此类对象的集合,这里的值(不是指针)是可以的

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

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

所以,实际问题是我无法实施上述解决方案。如果我按照上面的说明添加指针或 Role 对象,有人可以告诉我将在以前的代码中进行的更改吗?

如果 Movie 对象需要在 Actors 之间共享,另一种方法是使用 std::vector<std::shared_ptr<Movie>> 而不是 std::vector<Movie>std::vector<Movie*> .

std::vector<Movie> 之所以困难的原因基本上就是您所发现的。 Movie 对象与另一个 Movie 对象分开,即使 Movie 具有相同的名称。

那么 std::vector<Movie*> 会出现问题的原因是,是的,您现在可以“共享”Movie 对象,但是维护跟踪共享的数量 Movie 对象变得笨重。


std::vector<std::shared<Movie>> 进来帮忙。 std::shared_ptr 不仅仅是一个指针,而是一个智能指针,这意味着它将是一个引用计数指针,当所有对该对象的引用超出范围时,它将自行销毁。因此没有内存泄漏,这与您使用原始 Movie* 并以某种方式管理不善不同。

#ifndef ACTOR_H
#define  ACTOR_H

#include "Person.hpp"
#include "Movie.hpp"
#include <memory>

class Actor: public Person
{
  private:
    std::vector<std::shared_ptr<Movie>> movieList;

  public:
    void addMovie(std::shared_ptr<Movie> newMovie) {this->movieList.push_back(newMovie);}

    void printMovies()
    {
      for(auto& movie: this->movieList)
      {
        std::cout << movie->getTitle() << '\n';
      }
    }
};

#endif

然后将 类 的最小化版本和测试 main 函数放在一起:

#include <memory>
#include <vector>
#include <string>
#include <iostream>

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

class Person {};

class Actor: public Person
{
  private:
    std::vector<std::shared_ptr<Movie>> movieList;

  public:
    void addMovie(std::shared_ptr<Movie> newMovie) {this->movieList.push_back(newMovie);}

    void printMovies()
    {
      for(auto& movie: movieList)
      {
        std::cout << movie->getTitle() << "  Rating: " << movie->getRating() << '\n';
      }
    }
};

int main()
{
  // Create our movies 
  auto movie1 = std::make_shared<Movie>();
  auto movie2 = std::make_shared<Movie>();
  auto movie3 = std::make_shared<Movie>();        

  Actor actor1, actor2;
  
  movie1->setTitle("Transformers");
  movie2->setTitle("Interstellar");
  movie3->setTitle("The Matrix");

  actor1.addMovie(movie1); 
  actor1.addMovie(movie2);

  actor2.addMovie(movie1); 
  actor2.addMovie(movie3);
  
  std::cout << "actor 1 movies:\n";
  actor1.printMovies();
  std::cout << "\nactor 2 movies:\n";
  actor2.printMovies();
  
  // Set the rating to movie1 to "R"
  movie1->setRating("R");

  std::cout << "\n\nactor 1 movies:\n";
  actor1.printMovies();
  std::cout << "\nactor 2 movies:\n";
  actor2.printMovies();
  
}

输出:

actor 1 movies:
Transformers  Rating: G
Interstellar  Rating: G

actor 2 movies:
Transformers  Rating: G
The Matrix  Rating: G


actor 1 movies:
Transformers  Rating: R
Interstellar  Rating: G

actor 2 movies:
Transformers  Rating: R
The Matrix  Rating: G

现在 actor1actor2 实际上共享同一个 Movie,称为“变形金刚”——它们不再是独立的对象。我添加了 setRatinggetRating 函数来演示更改 movie1 的评级会将 actor1actor2 的评级更改为 R


现在,没有什么能阻止您制作另一部同名电影(例如,movie4 名为“变形金刚”的电影)。如果这是一个问题,您将需要一个额外的数据结构来跟踪已经使用的名称(可能是 std::unordered_set<std::string>)。但这是一个侧面点,只是为了让你知道这可能会发生。