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&lt;Date*&gt; 表明这个学校作业是个坏主意。考虑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);

请注意,像这样只实现&lt;&lt;=&gt;&gt;= 之一很有用。剩下的可以按照那个来实现。这样更容易不犯错误。

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

您还可以根据&lt; 实现==!=,尽管如果您有一个不等式的捷径,最好自己实现==

bool Date::operator== (const IComparable& other) const 
    return !(*this < other) && !(other < *this);


bool Date::operator!= (const IComparable& other) const 
    return !(*this == other);

【讨论】:

这真是太好了,谢谢。唯一要添加的是 D1 必须是一个常量,以及它转换为的类型,在插入这些更改之后,一切似乎都到位了。还要感谢仅使用该运算符的提示。我只是以返回的方式使用了更大和更改的东西的功能,但是您的想法更清晰。 @Merkava 可能不适用于您的任务,但您可以使用此模式仅实现 &gt; 等。人。一次,作为模板(或零次,使用an existing template) 如果类型不匹配,引用 dynamic_cast 已经抛出。无需重新发明***。 @n.'pronouns'm。这取决于您是要抛出std::bad_cast 还是::bad_compare @Caleth 公平点,但我认为在这个学术环境中你并不在乎。【参考方案3】:
return(larger(*this,*D1);

这是一个相当明显的语法错误 - 不匹配 (。先解决这个问题。

要从dynamic_cast 运算符中获取指针,我们需要传入一个指针(使用地址运算符&amp;)。此外,使用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&lt;Date&gt;IPrintable&lt;Date&gt; 基类而不改变行为。【参考方案5】:

来自 cppreference.com

dynamic_cast (表达式)

如果转换成功,dynamic_cast 返回一个新类型的值。如果转换失败并且 new-type 是指针类型,则返回该类型的空指针。如果转换失败并且 new-type 是一个引用类型,它会抛出一个与 std::bad_cast 类型的处理程序匹配的异常。

【讨论】:

这个问题的答案如何?

以上是关于C++:从抽象类重写纯虚运算符重载的主要内容,如果未能解决你的问题,请参考以下文章

在C++中,啥是运算符重载?啥是虚函数?

本周学习小结

通过最基础的例子讲解c++多态--没有更简单的了

通过最基础的例子讲解c++多态--没有更简单的了

通过最基础的例子讲解c++多态--没有更简单的了

运算符重载如何声明为纯虚函数?