指向派生 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 比较运算符可以用来比较不同类型电影的数字。
我有一部基础 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 比较运算符可以用来比较不同类型电影的数字。