指向派生 class 对象的 C++ Base class 指针不调用派生等于运算符函数

C++ Base class pointer pointing to derived class object doesn't call derived equal operator function

我有一部基础 class 电影和一些派生的 class 电影(FunnyMovie、DramaMovie、ClassicMovie)。我需要将它们存储在电影的二进制搜索树中。每部电影都有不同的排序参数。首先,我尝试对 FunnyMovies 进行排序。当我比较两个 FunnyMovie 对象时,会调用 FunnyMovie 等于运算符函数。但是当我比较两个包含搞笑电影的 Movie 指针时,会调用 Movie 等于运算符函数而不是 FunnyMovie 等于运算符函数。

如何让 Movie 指针调用它们所指向的(派生)对象的相等运算符函数而不是基础 class Movie 函数?

这是电影 Class:

#ifndef MOVIE_H
#define MOVIE_H
#include <sstream>
#include "RentableItem.h"
#include "Person.h"
using namespace std;

class Movie : public RentableItem
{
    friend ostream& operator<<(ostream &outStream, const Movie& movie);
public:
    Movie();
    Movie(int stock, string directorFirstName, string directorLastName, string title);
    ~Movie();

    string getTitle();
    Person& getDirector();
    char getMediaType();

    virtual bool operator==(const Movie& rhsMovie)const;
    virtual bool operator!=(const Movie& rhsMovie)const;
    virtual bool operator<(const Movie& rhsMovie) const;
    virtual bool operator>(const Movie& rhsMovie) const;
    virtual bool operator<=(const Movie& rhsMovie)const;
    virtual bool operator>=(const Movie& rhsMovie)const;

protected:
    Person* director;   // address
    string title;
    char mediaType;    // it is "D" for all movies as DVD.
};

#endif

这是 Movie 相等运算符的实现:

#include "Movie.h"
using namespace std;

bool Movie::operator==(const Movie& rhsMovie)const
{
    return (*this->director == *rhsMovie.director && this->mediaType == rhsMovie.mediaType &&
        this->title == rhsMovie.title);
}

这是搞笑电影class:

#ifndef FUNNYMOVIE_H
#define FUNNYMOVIE_H
#include "Movie.h"
using namespace std;

class FunnyMovie : public Movie
{
    friend ostream& operator<<(ostream &outStream, const FunnyMovie& movie);
public:
    FunnyMovie();
    FunnyMovie(int stock, string directorFirstName, string directorLastName,
        string title, int releaseYear);
    ~FunnyMovie();

    int getReleaseYear();
    bool operator==(const FunnyMovie& rhsMovie)const;
    bool operator!=(const FunnyMovie& rhsMovie)const;
    bool operator<(const FunnyMovie& rhsMovie)const;
    bool operator>(const FunnyMovie& rhsMovie)const;
    bool operator<=(const FunnyMovie& rhsMovie)const;
    bool operator>=(const FunnyMovie& rhsMovie)const;

private:
    int releaseYear;
};

#endif

这里是相等运算符的 FunnyMovie 实现:

#include "FunnyMovie.h"
using namespace std;

FunnyMovie::FunnyMovie()
{
    releaseYear = 0;
}

FunnyMovie::FunnyMovie(int stock, string directorFirstName, string  directorLastName,
    string title, int releaseYear) : Movie(stock, directorFirstName, directorLastName, 
    title)
{
    this->releaseYear = releaseYear;
}

FunnyMovie::~FunnyMovie()
{
}

bool FunnyMovie::operator==(const FunnyMovie& rhsMovie)const
{
    return (this->title == rhsMovie.title && this->releaseYear == rhsMovie.releaseYear);
}

我想可能不是调用 FunnyMovie 方法,因为它们没有相同的参数,所以我改变了

bool FunnyMovie::operator==(const FunnyMovie& rhsMovie)const
// to:
bool FunnyMovie::operator==(const Movie& rhsMovie)const

但是 Movie 对象没有 releaseYear,而 releaseYear 对于 FunnyMovie 排序是必不可少的。

要使虚函数在派生 classes 上运行,它必须具有与基 class 相同的签名。所以你的 operator==() 必须有一个 const Movie & 参数。

我还没有尝试过,但是为了使您的匹配更加具体,我想尝试使用动态转换。类似下面的内容。

// The "override" clause makes sure that the virtual function signature matches the one in the base class
bool FunnyMovie::operator==(const Movie &other) const override {
  bool result=false; // Presume different.

  FunnyMovie *fm_other=dynamic_cast<FunnyMovie *>(&other);
  if(fm_other){
    // Perform FunnyMovie comparison with ‘fm_other’ and set ‘result’.
  }
  else{
    // Perform generic Movie comparison with ‘other’ and set ‘result’.
  }

  return result;
}

回答你的问题,理由是:

Movie& a = PickAFunnyMovie();
Movie& b = PickAFunnyMovie();

if (a==b) printf("Same\n");

不调用 FunnyMovie::operator == 是因为您没有在派生的 class 中覆盖它。覆盖时总是喜欢使用 override 关键字——这意味着如果你弄错了,编译器会警告你。因此,您绝对必须将 FunnyMovie 中的声明更改为:

bool operator ==(const Movie& rhs) const;

所以在定义中,你将不得不写这样的东西:

bool FunnyMovie::operator ==(const Movie& rhs) const
{
    auto pRhs = dynamic_cast<const FunnyMovie*>(&rhs);
    if (!pRhs) return false;  // Not a funny movie - must be different.

    // Now you can access `ReleaseYear` through `pRhs` 
}

对于 operator <() 这样的比较,您将不得不决定如何对不同的电影进行排序。

实际上,更好的路线是:

bool operator <(const Movie& rhs) const
{
   const auto lhs_type = typeid(*this);
   const auto rhs_type = typeid(rhs);

   if (lhs_type == rhs_type)
       return cmp(rhs)
   else
       return lhs_type.before(rhs_type);
}

不会 覆盖、隐藏或重载比较运算符 - 您只需使用基础 class 实现。您必须重载的唯一函数是 int cmp(const Movie&rhs) const,其中 returns 0、-1、1 作为 *this 分别等于、小于或大于 rhs。基础 class 保证 rhs*this 的类型相同,因此您可以 dynamic_cast 引用,而不必检查转换失败。

请注意,此技术将提供 不同电影类型的排序 - 如果您想选择特定类型,您还需要提供基础 class一个虚拟 getClassOrder 函数,其中 returns 比较运算符可以用来比较不同类型电影的数字。