1

我正在尝试创建一些使用继承类的重载算术运算符,如下所示:

class Block {
    public:
        Block() {}
        virtual double Value() {};
};

class Constant : public Block {
    public:     
        Constant(double v) { value = v; }
        virtual double Value() { return value; }
    private:
        double value;       
};

class Add : public Block {
    public:
        Add(Block &a, Block &b) { value1 = &a; value2 = &b; }
        virtual double Value() { return value1->Value() + value2->Value(); }
    private:
        Block *value1;
        Block *value2;          
};

Block operator + (Block &a, Block &b) {
    return new Add(a, b);
}

int main() {
    Constant a(5.0);
    Constant b(6.0);
    printf("%.3f", (a+b).Value());
}

但我得到以下信息:error: conversion from 'Add*' to non-scalar type 'Block' requested

这是我第一次在 C++ 中使用 OOP,所以我的想法是否可行?

4

2 回答 2

5

作为一般规则,运算符重载和继承不能很好地协同工作,因为在 C++ 中,运算符通常具有值语义。然而,有一个主要的例外,如果你的Add类的所有实例实际上都是你的operator+(临时)的返回值,那么你已经有效地实现了编译时表达式评估——一种非常重要的优化技术。(在现代 C++ 中,这通常是使用模板完成的,而不是继承,但原理是一样的。)

因为运算符具有值语义,所以它们应该返回值,而不是指针。这意味着没有new。不使用的另一个原因new是任何被newed 的东西都必须显式删除,并且在大多数情况下,没有办法显式删除作为表达式的一部分返回的指针。并且这样的指针也必须被取消引用。

编辑:

我似乎忘记了重要的一点:运算符的声明返回值必须是您返回的实际类型,因为您的返回表达式将被复制到该类型中。因此:

Add
operator+( Block const& lhs, Block const& rhs )
{
    return Add( lhs, rhs );
}

也请注意const. 没有它,你不能在临时工上使用操作符;ega + b + c将是非法的(假设 a,bc属于 类型Block,或者是从它派生的某种类型)。

于 2012-12-03T10:06:24.693 回答
4

由于您没有提及导致错误的代码的特定部分,因此让我指出:

Block operator + (Block &a, Block &b) {
    return new Add(a, b);
}

这里到底发生了什么?好吧,您承诺返回 a Block,但实际上您正在返回new Add(a, b),即 a Add*。这就是编译器所抱怨的。

这是我第一次在 C++ 中使用 OOP

可以从所有的指针、新闻和虚拟变量中看出。您的代码存在严重的生命周期问题。

我强烈建议您忘记您的 C++ OOP 知识并阅读一本很好的 C++ 入门书籍

于 2012-12-03T09:49:16.527 回答