【问题标题】:How does operator overloading work, and why doesn't it work in my case?运算符重载如何工作,为什么它在我的情况下不起作用?
【发布时间】:2019-02-23 03:49:43
【问题描述】:

我得到了一个驱动程序函数,它应该演示涉及复数的运算符重载的结果。在阅读了一段时间的重载后,我设法以一种成功编译的方式编写了代码,但是在此过程中,程序没有输出正确的值。

据我了解,重载本质上就像一个函数。传递对象,然后“函数”可以对其进行算术/任何操作并返回一个新对象。不过,我有点迷失的是,重载如何知道正在传递什么值。例如,在我的例子中,我重载了“+”和“=”运算符,以便以“x =​​ y + z”的形式添加两个复数。当编译器遇到“=”符号时,我假设它只是传递左侧和右侧的任何内容并传递那些?与“+”相同。在这种情况下,它会传递“y”,因为它是左侧的对象,而“z”是因为它是右侧的对象?

这是我当前的“复杂”类,其中包括重载定义。

class Complex {

private:
double realPart;
double imaginaryPart;

public:
// friends
friend ostream & operator<<(ostream &out, const Complex &c);
friend istream & operator>>(istream &in,  Complex &c);

// constructors
Complex()
{
    realPart = 0;
    imaginaryPart = 0;
}

Complex(double real)
{
    realPart = real;
    imaginaryPart = 0;
}

Complex(double real, double imaginary)
{
    realPart = real;
    imaginaryPart = imaginary;
}
// end of constructors

// + overloading
Complex operator+(Complex const &c)
{
    Complex Add;
    Add.realPart = realPart + c.realPart;
    Add.imaginaryPart = imaginaryPart + c.imaginaryPart;
    return Add;
}

// - overloading
Complex operator-(Complex const &c)
{
    Complex Subtract;
    Subtract.realPart = realPart - c.realPart;
    Subtract.imaginaryPart = imaginaryPart - c.imaginaryPart;
    return Subtract;
}

// * overloading
Complex operator*(Complex const &c)
{
    Complex Multiply;
    Multiply.realPart = (realPart * c.realPart) - (imaginaryPart * c.imaginaryPart);
    Multiply.imaginaryPart = (realPart * c.imaginaryPart) - (imaginaryPart * c.realPart);
    return Multiply;
}

// = overloading
Complex operator=(Complex const &c)
{
    Complex Assignment;
    Assignment.realPart = realPart;
    Assignment.imaginaryPart = imaginaryPart;
    return Assignment;
}

// == overloading
bool operator==(Complex const &c)
{
    Complex Compare;
    if (Compare.realPart == realPart && Compare.imaginaryPart == imaginaryPart)
    {
        return true;
    }
    else
    {
        return false;
    }
}

    // != overloading
bool operator!=(Complex const &c)
{
    Complex NotEqual;
    if (NotEqual.realPart == realPart && NotEqual.imaginaryPart == imaginaryPart)
    {
        return false;
    }
    else
    {
        return true;
    }
}

};

// << overloading
ostream& operator<<(ostream& out, const Complex &c)
{
    out << c.realPart;
    if (c.imaginaryPart >= 0)
    {
        out << " + " << c.imaginaryPart << "i" << endl;
    }
    else
    {
        out << " - " << fabs (c.imaginaryPart) << "i" << endl;
    }

    return out;
}

// >> overloading
istream& operator>>(istream &in, Complex &c)
{
    in >> c.realPart;
    in >> c.imaginaryPart;
    return in;
}

这是驱动程序:

int main()
{
    for (double i = 1; i < 10; ++ i)
    {
        Complex y{i * 2.7, i + 3.2};
        Complex z{i * 6, i + 8.3};

        Complex x;
        Complex k;

        std::cout << "Enter a complex number in the form: (a, b)\n? ";
        std::cin >> k; // demonstrating overloaded >>
        std::cout << "x: " << x << "\ny: " << y << "\nz: " << z << "\nk: " << k << '\n'; // demonstrating overloaded <<

        x = y + z; // demonstrating overloaded + and =
        std::cout << "\nx = y + z:\n" << x << " = " << y << " + " << z << '\n';
        x = y - z; // demonstrating overloaded - and =
        std::cout << "\nx = y - z:\n" << x << " = " << y << " - " << z << '\n';
        x = y * z; // demonstrating overloaded * and =
        std::cout << "\nx = y * z:\n" << x << " = " << y << " * " << z << "\n\n";

        if (x != k)
        { // demonstrating overloaded !=
            std::cout << x << " != " << k << '\n';
        }

        std::cout << '\n';
        x = k;

        if (x == k)
        {
            // demonstrating overloaded ==
            std::cout << x << " == " << k << '\n';
        }

        std::cout << std::endl;
}
}

运行时,问题似乎出在对象“x”上。输入“5 2”仍将输出“x: 0 + 0i” 这让我相信问题出在“=”或流运算符的重载上。也就是说,我不太明白为什么什么也没发生。

我认为“=”重载定义的构建方式是否有错误,或者可能是我遗漏了更大的东西?

【问题讨论】:

  • 对于operator= - 分配 - 您实际上忽略了为实例分配 值。赋值以这种方式不与+、-等平行。
  • 您的 +、- 和 * 运营商看起来不错。您的 operator= 应该分配给 this 以便按预期工作,并且应该按照约定返回对 *this 的引用。你的 operator== 和 operator!= 忽略他们的输入,而是与一个无用的临时对象进行比较。
  • 要回答“运算符重载是如何工作的”,您似乎已经大致弄清楚了,但这里有一个很好的彻底阅读:What are the basic rules and idioms for operator overloading?
  • 建议 -- 您的 != 应该是一个简单的单行:{ return !(this == c);}。使用已经写好的内容。

标签: c++ overloading operator-keyword


【解决方案1】:

您的= 错误;它应该返回*this。

Complex& operator=(Complex const &c)
{
  realPart = c.realPart;
  imaginaryPart = c.imaginaryPart;
  return *this;
}

解决这个问题,其余大部分看起来都很正常。

【讨论】:

  • 谢谢,成功了!我仍然不太确定我得到返回“*this”的作用。它只是指向该本地对象的指针吗?
  • @Cartino Complex&amp; 的返回类型是对Complex 的引用,基本上是已经存在的Complex 类型变量的另一个名称。 *this 取消引用 this 指针以获取值而不是地址。这提供了一个现有变量来返回对调用者的引用
  • @cartino 在 C/C++ 中,a=b=c 是 a=(b=c)——来自b=c 的返回被分配给a,通常这是通过从@987654334 返回b 来完成的@ 引用。 operator= 返回void 也是合理的,因为现在谁用= 那样?
【解决方案2】:

operator=() 不正确:用户Yakk - Adam 已经向您展示了如何修复它。让您了解错误的原因以及return *this 的作用;让我们看看你原来的功能:

Complex operator=(Complex const &c) {
    Complex Assignment;
    Assignment.realPart = realPart;
    Assignment.imaginaryPart = imaginaryPart;
    return Assignment;
}

在这里,您的签名对另一个 Complex 对象进行了 const 引用,这部分是正确的。您的返回类型是 Complex 对象,这本质上是错误的,因为您不想返回对象的副本。这里的目标是执行分配。这意味着您必须对原始的 LHS 实例进行更改。

在表达式A = B + C中; A 被认为是 LHS 实例。在这里,您要分配表达式(B + C),它们都是RHS 值。

所以当Yakk - Adam 向您展示如何解决这个问题时:

Complex& operator=(Complex const &c) {
  realPart = c.realPart;
  imaginaryPart = c.imaginaryPart;
  return *this;
}

这里的一个区别是返回类型现在是特定对象的Reference,而不是对象的副本。

另一个区别是不需要像在原始版本中那样创建本地临时副本:

Complex Assignment; // this is not needed

通过从operator=() 中删除它,他只是替换了这些代码行:

// Assignment.realPart = realPart; // To
realPart = c.realPart;
// Assignment.imaginaryPart = imaginaryPart; // To
imaginaryPart = c.imaginaryPart;

在这里,您直接使用类的成员并将属于另一个的值或传递给运算符的c 分配给它们。

然后最后返回您的 LHS 实例和更新的值;这是你必须返回一个取消引用的 this 指针的地方。

*this 是什么意思? this 指针是属于所有class 和struct 类型的特殊指针。例如,任何时候你有类对象:

class Foo {
public:
    int bar { 10 };

    void addFive();
}; 

您可以直接在成员函数中使用 this 指针:

void Foo::addFive() {
    this->bar += 5; // same as below  (this) belongs to this particular instance.
    // bar += 5;        
}

关于你的operator=();由于您是通过reference 返回的,因此您不能简单地只是return this。这将返回 this 指针。我们不想要指向对象的指针,因为我们想要对对象的引用;所以我们必须通过返回*this来尊重this指针。

我希望这可以帮助您解决问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-10-21
    • 2018-06-25
    • 2020-09-20
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 2019-10-08
    相关资源
    最近更新 更多