我有一个基类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排序至关重要。
答案 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
函数,返回比较运算符可用于比较不同类型的电影的数字。