重载纯虚拟运算符

Overloading pure virtual operators

我有抽象 class Number 和 4 个纯虚拟运算符(+-/*)。我想制作两个派生的 classes IntegerReal 并在那里覆盖这些运算符。我不太了解如何声明运算符。我在网上没有找到类似我情况的例子。

我的问题是: 在抽象基础 class Number 中,我的运算符必须 return 引用 Number& 或指针 Number*,因为我不能 return 抽象 class 本身。但是我应该传递什么作为参数呢? Number&Number* 也是,但是我需要在 class 中存储数字,我应该在我的基础 class 中有类似 void* num 的东西吗? 想象一下,我有

class Number {
    ...
    virtual Number& operator+(const Number&) = 0;
};

我应该如何在派生 class Integer 中覆盖此运算符?

I know, but my tutor insist on doing it as overriding pure virtual operator as exercising in abstract classes, but I really don't get it.

嗯,你可以从中了解到两件事:

  1. 虚函数的一般工作原理(自定义运算符与普通函数无异,只是调用语法不同)。
  2. 虚函数不是解决任何问题的圣杯。

问题是 类 IntegerReal 很可能具有不同的内部表示 - 因此您将无法执行 addition/multiplication/。 .. 不知道你作为第二个操作数收到的具体类型。此外,还不清楚 return 类型的混合操作数类型应该是什么。

I don't really need atm to add real+int only real+real, int+int

好吧,我们可以抓住这个:

class Number
{
public:
    virtual ~Number() { } // in any case, a virtual base class should have a virtual destructor!

    // fine so far:
    virtual Number& operator+(Number const&) const = 0;
    // we are not going to change the          ^
    // own instance, so we'd rather have this operator const
    // (in contrast to operator+=)
};

class Integer : public Number
{
public:
    Integer& operator+(Number const& other) const override
    // ^ co-variant return type, so that's fine
    {
        // at very first, we make sure that we actually received
        // an instance of type Integer
        auto o = dynamic_cast<Integer const*>(&other);
        if(!o)
            // if not, throwing an exception is a good candidate
            // for error handling...
            throw std::invalid_argument("argument must be of type Integer");

        // now as we know it IS an Integer:
        return Integer(this->value + o->value); // or whatever...
        // OOPS - the returned object gets lost when the function is left...
    }
};

如果您也希望能够添加 Real,那么您需要进行另一种类型转换。假设 Integer + Real 结果为 Real,那么您必须将 return 类型改回 Number

然而,仍然存在一个很大的问题:returned 对象在函数离开后立即被销毁,因此引用 returned 是悬空的。

我们必须通过某种方式解决这个问题。但是引用不合适,所以我们可能会选择智能指针:

class Number
{
    virtual std::unique_ptr<Number> operator+(Number const&) const = 0;
};

class Integer : public Number
{
    std::unique_ptr<Number> operator+(Number const& other) const override
    //                 ^
    // unfortunately, now, as ordinary struct, no co-variance possible any more
    {
        return std::make_unique<Integer>(this->value + o->value);
    }
};

这个问题再次说明实际选择的方法是多么不合适...