C++:从抽象类重写纯虚运算符重载
Posted
技术标签:
【中文标题】C++:从抽象类重写纯虚运算符重载【英文标题】:C++: overriding a pure virtual operator overload from an abstract class 【发布时间】:2020-01-20 10:17:44 【问题描述】:我在学校的作业要求我为虚拟运算符重载构建一个抽象类,然后构建一个使其工作的类。 具体来说:IComparable - 摘要
class IComparable
public:
virtual bool operator== (const IComparable&) const = 0;
virtual bool operator< (const IComparable&) const = 0;
virtual bool operator> (const IComparable&) const = 0;
virtual bool operator!= (const IComparable&) const = 0;
virtual bool operator<= (const IComparable&) const = 0;
virtual bool operator>= (const IComparable&) const = 0;
;
和日期 - 实际类
class Date : public IPrintable, IComparable
private:
int day;
int month;
int year;
public:
Date(int, int, int);
void setDay(int);
void setMonth(int);
void setYear(int);
bool Comparison(const Date&, const Date&) const;
bool larger(const Date&, const Date&) const;
bool operator== (const IComparable& other)const override;
bool operator< (const IComparable& other)const override;
bool operator> (const IComparable& other)const override;
bool operator!= (const IComparable& other)const override;
bool operator<= (const IComparable& other)const override;
bool operator>= (const IComparable& other)const override;
~Date();
;
当我尝试在 Date.cpp 中实现它时出现问题
我真的不知道该怎么做。
我以为我应该使用 dynamic_cast 将 IComparable 向下转换为 Date 以在函数中使用。但是我遇到了问题。我尝试了一些不同的实现,我会把它们扔在这里,以防万一它们中的一个接近我必须做的。
bool Date::operator< (const IComparable& other)const override
Date *D1 = dynamic_cast<Date*>(other);
return(larger(*this,*D1);
bool Date::operator> (const IComparable& other)const override
return(larger(other, *this));
bool Date::operator!= (const IComparable& other)const
bool Flip;
Flip = Comparison(*this, other);
return(!Flip);
我需要输入覆盖吗?因为它显示为错误“期望一个”
总的来说,我做错了什么。 提前致谢。
【问题讨论】:
在第一个变量中,您尝试将引用转换为指针。这通常不起作用。选择一件事(很可能是参考)。另外两个只是在转移污垢。在某些地方你需要投射。 那我怎么寄过去呢? "larger" 函数检查右侧是否大于左侧,因此它需要能够将“其他”私有成员视为 Date 类。那我怎么看下去呢? 除此之外:你必须dynamic_cast<Date*>
表明这个学校作业是个坏主意。考虑class Address : IComparable
,问Date
是否小于Address
有意义吗?
就像比较不同的班级一样?不,听起来不对。是的,这门课的作业从来都不是很好。非常令人费解,有多个程序员说如果他们想找到一份工作,没有人应该那样写东西。但是,我必须为此使用 IComparable.h 和 Date,h 和 cpp。任务还有更多内容,但现在无关紧要
“我在学校的作业要求我为虚拟运算符重载构建一个抽象类” 在 C++ 中似乎不是一个好方法。
【参考方案1】:
您永远无法将具体事物与抽象事物进行比较。这就像问“这本书和一般阅读材料哪个更贵?”。 要解决这个问题,您需要将两个论点具体化。
执行此操作的常规方法是使用称为double dispatch 的模式。 走这条线……
bool operator== (const IComparable& other)const override;
你怎么可能实现这个功能?想想看。该函数知道“this”是一个日期,但其他的是什么?它可以是从 IComparable 派生的任何东西。 IComparable 对自身的唯一声明就是具有可比性。
在双重分派中,您使用的事实是每个函数都必须知道它自己的类型。然后它在第二个参数上调用一个具体的比较方法,将它自己作为参数传递。然后,此函数知道两个参数的类型,并可能解决问题。 这显示在上面的“C++ 中的双重调度”下的***页面上。
【讨论】:
DD 在这里可能有点矫枉过正。如果您有 N 种类型和 O(N*N) 操作(想想算术类型),那就太好了。但在这里您不会将日期与雪佛兰进行比较。【参考方案2】:你的第一次尝试几乎是正确的
bool Date::operator< (const IComparable& other) const // no override in out-of-line definition
const Date *D1 = dynamic_cast<const Date*>(&other); // cast pointer to other, retaining constness
// throw if D1 == nullptr?
return larger(*this,*D1);
你也可以
bool Date::operator< (const IComparable& other) const // no override in out-of-line definition
const Date& D1 = dynamic_cast<const Date&>(other); // will throw if other isn't a Date
return larger(*this, D1);
请注意,像这样只实现<
、<=
、>
和>=
之一很有用。剩下的可以按照那个来实现。这样更容易不犯错误。
bool Date::operator<= (const IComparable& other) const
return !(other < *this);
bool Date::operator> (const IComparable& other) const
return other < *this;
bool Date::operator>= (const IComparable& other) const
return !(*this < other);
您还可以根据<
实现==
和!=
,尽管如果您有一个不等式的捷径,最好自己实现==
。
bool Date::operator== (const IComparable& other) const
return !(*this < other) && !(other < *this);
bool Date::operator!= (const IComparable& other) const
return !(*this == other);
【讨论】:
这真是太好了,谢谢。唯一要添加的是 D1 必须是一个常量,以及它转换为的类型,在插入这些更改之后,一切似乎都到位了。还要感谢仅使用该运算符的提示。我只是以返回的方式使用了更大和更改的东西的功能,但是您的想法更清晰。 @Merkava 可能不适用于您的任务,但您可以使用此模式仅实现>
等。人。一次,作为模板(或零次,使用an existing template)
如果类型不匹配,引用 dynamic_cast 已经抛出。无需重新发明***。
@n.'pronouns'm。这取决于您是要抛出std::bad_cast
还是::bad_compare
@Caleth 公平点,但我认为在这个学术环境中你并不在乎。【参考方案3】:
return(larger(*this,*D1);
这是一个相当明显的语法错误 - 不匹配 (
。先解决这个问题。
要从dynamic_cast
运算符中获取指针,我们需要传入一个指针(使用地址运算符&
)。此外,使用dynamic_cast
而不检查结果的有效性也没有什么意义——如果other
不是Date
,我们将得到nullptr
。
bool Date::operator< (const IComparable& other) const
auto *other_date = dynamic_cast<const Date*>(&other);
if (!other_date) return false;
return larger(*this,*other_date);
或者,我们坚持使用引用,但捕获 std::bad_cast
异常而不是测试 null:
bool Date::operator< (const IComparable& other) const
try
auto &other_date = dynamic_cast<const Date&>(&other);
return larger(*this,other_date);
catch (std::bad_cast&)
return false;
请注意,这两个版本仍然很差,因为我们没有在此处提供所有 IComparable
对象的良好总排序 - 这是此类接口在 C++ 中是一个坏主意的主要原因(也许这是为了这里的教学课?)。
【讨论】:
如果other
不是Date
,我不会return false
@Caleth,你会返回什么?
@TobySpeight 因为你不能返回任何有意义的东西,所以抛出一个异常。【参考方案4】:
我找到了另一种方法来处理这个问题,这很有意义。 我们把 IComparable 变成这样的模板类:
template<typename T>
class IComparable
public:
virtual bool operator== (const T&) const = 0;
virtual bool operator< (const T&) const = 0;
virtual bool operator> (const T&) const = 0;
virtual bool operator!= (const T&) const = 0;
virtual bool operator<= (const T&) const = 0;
virtual bool operator>= (const T&) const = 0;
;
然后用 IComparable 声明日期 这样一来,我们就可以让 Comparable 充满纯虚拟,而不会受到整个 dynamic_cast 问题的影响
class Date : public IPrintable<Date>, IComparable<Date>
.
.
.
bool larger(const Date&, const Date&) const;
bool operator== (const Date &other)const;
bool operator< (const Date &other)const;
.
.
【讨论】:
这违背了virtual
的全部观点。您也可以在这里删除 IComparable<Date>
和 IPrintable<Date>
基类而不改变行为。【参考方案5】:
来自 cppreference.com
dynamic_cast (表达式)
如果转换成功,dynamic_cast 返回一个新类型的值。如果转换失败并且 new-type 是指针类型,则返回该类型的空指针。如果转换失败并且 new-type 是一个引用类型,它会抛出一个与 std::bad_cast 类型的处理程序匹配的异常。
【讨论】:
这个问题的答案如何?以上是关于C++:从抽象类重写纯虚运算符重载的主要内容,如果未能解决你的问题,请参考以下文章