指向派生类对象的C ++基类指针不会调用派生的相等运算符函数

时间:2015-12-11 20:50:05

标签: c++ pointers polymorphism virtual base-class

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

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

这是电影类:

#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 equal运算符实现:

#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);
}

这是FunnyMovie课程:

#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排序至关重要。

2 个答案:

答案 0 :(得分:3)

要使虚函数处理派生类,它必须具有与基类相同的签名。因此,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;
}

答案 1 :(得分:1)

回答你的问题,原因是:

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

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

不调用FunnyMovie::operator ==是因为您没有在派生类中重写它。在覆盖时总是更喜欢使用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);
}

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

请注意,此技术将提供 对不同Movie类型的排序 - 如果要选择特定类型,则还需要为基类提供虚拟getClassOrder函数,返回比较运算符可用于比较不同类型的电影的数字。