【问题标题】:Overloaded postincrement operator squares value of complex number without instantiation of operator重载后增量运算符平方值的复数没有实例化运算符
【发布时间】:2017-06-30 19:59:17
【问题描述】:

这是输出:

First Complex Number:
Enter real part of complex number: 3
Enter imaginary part of complex number: 6

Second Complex Number:
Enter real part of complex number: 5
Enter imaginary part of complex number: -5

a == (-27.00+36.00i)
b == (5.00-5.00i)
a+b == (-22.00+31.00i)
a-b == (-32.00+41.00i)
a*b == (45.00+315.00i)
a*a == (-567.00-1944.00i)
b*b == (0.00-50.00i)
a*a (using postincrement) ==(-27.00+36.00i)

如您所见,并非所有涉及a 的内容都是错误的,因为它将a(一个复数)的平方作为a。所以,虽然“a*a (using postincrement) == (-27.00+36.00i)”的答案是正确的答案......它说“a == (-27.00+36.00i)”的部分是不正确的,因为它应该是a==(3+6i)。我相信错误在于重载和朋友方面我的代码,但我不知道如何修复它,因为我没有给出任何错误......这是我代码中的逻辑问题。

这是我的代码:

#include<iostream>
#include<iomanip>
using namespace std;

class ComplexNum
{
public:
    ComplexNum(float = 0.0, float = 0.0); //default constructor that uses default arg. in case no init. are in main
    ComplexNum& getComplexNum(); //get real and imaginary numbers from keyboard
    ComplexNum& sum(ComplexNum a, ComplexNum b); //method to add two ComplexNum numbers together
    ComplexNum& diff(ComplexNum a, ComplexNum b); //method to find the difference of two complex numbers
    ComplexNum& prod(ComplexNum a, ComplexNum b); //method to find the product of two complex numbers
    ComplexNum& square(ComplexNum a); //method to find square using pre/post increment operators

    //overloaded operators
    ComplexNum& operator =  (const ComplexNum& that) = default;
    ComplexNum& operator += (const ComplexNum& that) { return sum(*this, that); }
    ComplexNum& operator -= (const ComplexNum& that) { return diff(*this, that); }
    ComplexNum& operator *= (const ComplexNum& that) { return prod(*this, that); }
    ComplexNum& operator ++() { return square(*this); } //called for ++num
    ComplexNum& operator ++(int) { return square(*this); } //called for num++

    ostream& print(ostream& stm = cout) const;


private:
    float real; //float data member for real number (to be entered in by user)
    float imaginary; //float data member for imaginary number (to be entered in by user)

    //non-member overloaded operators
    //a is passed by value
    friend ComplexNum operator+ (ComplexNum a, const ComplexNum& b) { return a += b; }
    friend ComplexNum operator- (ComplexNum a, const ComplexNum& b) { return a -= b; }
    friend ComplexNum operator* (ComplexNum a, const ComplexNum& b) { return a *= b; }
    friend ComplexNum operator++(ComplexNum a) { return a++; }

    friend ostream& operator<< (ostream& stm, const ComplexNum& c) { return c.print(stm); }
};

ComplexNum::ComplexNum(float a, float b)
{
    real = a;
    imaginary = b;
}

ComplexNum& ComplexNum::getComplexNum()
{
    ComplexNum keyboard;
    cout << "Enter real part of complex number: ";
    cin >> real;

    cout << "Enter imaginary part of complex number: ";
    cin >> imaginary;

    return keyboard; 
}

ComplexNum& ComplexNum::square(ComplexNum a)
{
    this->real = (a.real * a.real) - (a.imaginary * a.imaginary);
    this->imaginary = (2 * (a.real * a.imaginary));
    return *this;
}

ComplexNum& ComplexNum::sum(ComplexNum a, ComplexNum b)
{
    this->real = a.real + b.real;
    this->imaginary = a.imaginary + b.imaginary;
    return *this;
}

ComplexNum& ComplexNum::diff(ComplexNum a, ComplexNum b)
{
    this->real = a.real - b.real;
    this->imaginary = a.imaginary - b.imaginary;
    return *this;
}

ComplexNum& ComplexNum::prod(ComplexNum a, ComplexNum b)
{
    this->real = (a.real * b.real) - (a.imaginary * b.imaginary);
    this->imaginary = (a.real * b.imaginary) + (b.real * a.imaginary);
    return *this;
}

ostream& ComplexNum::print(ostream& stm) const
{
    return stm << "(" << noshowpos << real << showpos << imaginary << "i)";
}

int main()
{
    ComplexNum a, b;
    cout << "First Complex Number:" << endl;
    a.getComplexNum();
    cout << endl;
    cout << "Second Complex Number:" << endl;
    b.getComplexNum();
    cout << endl;
    cout << fixed << setprecision(2)
        << "a == " << a << '\n'
        << "b == " << b << '\n'
        << "a+b == " << a + b << '\n'
        << "a-b == " << a - b << '\n'
        << "a*b == " << a*b << '\n'
        << "a*a == " << a*a << '\n'
        << "b*b == " << b*b << '\n'
        << "a*a (using postincrement) ==" << a++ << '\n';
        cout << endl;

    system("PAUSE");
}

【问题讨论】:

  • ComplexNum&amp; getComplexNum(); -- 这个函数在哪里?
  • 使用a++ 会破坏输出中a 的所有其他用法。
  • @gary - 对cout(很多!)的参数评估顺序未指定,因此您无法判断增量何时发生。
  • @garyoak 正如前面的评论所指出的,你在getComplexNum() 中确实有一个错误。您正在返回对局部变量的引用,这是未定义的行为。所以基本上,你得到的任何输出都是假的,即使你修复了++ 问题。只需按值而不是引用返回 ComplexNum
  • Prefix-++ 应该通过引用返回,而 postfix-++ 应该按值返回(你搞砸了两次)

标签: c++ operator-overloading post-increment


【解决方案1】:

这不是关于运算符重载,而是关于order of evaluation

在声明中:

cout << fixed << setprecision(2)
        << "a == " << a << '\n'
        << "b == " << b << '\n'
        << "a+b == " << a + b << '\n'
        << "a-b == " << a - b << '\n'
        << "a*b == " << a*b << '\n'
        << "a*a == " << a*a << '\n'
        << "b*b == " << b*b << '\n'
        << "a*a (using postincrement) ==" << a++ << '\n';

如您所料,参数将从左到右打印,但计算每个参数的各个步骤不必按此顺序完成。

编译器可以以任何顺序计算每个子表达式的值,只要在需要打印时该值是“准备好”的。所以它可以做这样的事情:

auto&& temp1 = a + b;
auto&& temp2 = a - b;
auto&& temp3 = a*b;
auto&& temp4 = a*a;
auto&& temp5 = b*b;
auto&& temp6 = a++;
cout << fixed << setprecision(2)
        << "a == " << a << '\n'
        << "b == " << b << '\n'
        << "a+b == " << temp1 << '\n'
        << "a-b == " << temp2 << '\n'
        << "a*b == " << temp3 << '\n'
        << "a*a == " << temp4 << '\n'
        << "b*b == " << temp5 << '\n'
        << "a*a (using postincrement) ==" << temp6 << '\n';

如果发生这种情况,您将得到您所期望的行为,因为子表达式将按从左到右的顺序进行计算。但是当前的 C++ 标准 (C++14) 允许编译器重新排序评估,如果它需要更少的堆栈空间和更少的寄存器,这可能允许它更好地优化代码。该语句的另一个有效执行是:

auto&& temp1 = a++;
auto&& temp2 = b*b;
auto&& temp3 = a*a;
auto&& temp4 = a*b;
auto&& temp5 = a - b;
auto&& temp6 = a + b;
cout << fixed << setprecision(2)
        << "a == " << a << '\n'
        << "b == " << b << '\n'
        << "a+b == " << temp6 << '\n'
        << "a-b == " << temp5 << '\n'
        << "a*b == " << temp4 << '\n'
        << "a*a == " << temp3 << '\n'
        << "b*b == " << temp2 << '\n'
        << "a*a (using postincrement) ==" << temp1 << '\n';

这一次你可以看到a++操作首先发生,所以后面的计算将在发生之后进行。

编译器还可以选择子表达式求值的任何其他顺序,例如它可以评估a*a 然后++a 然后a-b 等等(但实际上最常见的顺序是从左到右和从右到左)


顺便说一句,您的代码还有另外两个严重问题:

这个函数返回一个局部变量的引用:

ComplexNum& ComplexNum::getComplexNum()
{
    ComplexNum keyboard;
    // ...
    return keyboard; 
}

函数返回后,该局部变量不再存在,因此任何使用引用的尝试都会访问一个不存在的对象。 永远不要这样做!你的编译器应该警告你这里有问题,启用你的编译器的警告并且不要忽略它们!

其次,重载像++ 这样的运算符来表示完全不同的东西,比如将对象自身相乘,这是一个真的坏主意。仅当运算符对您要执行的操作有意义时,才应使用运算符重载。递增不是平方,所以这是一个糟糕的选择。我只想为此定义一个普通(非操作员)函数。

【讨论】:

    猜你喜欢
    • 2010-10-14
    • 2010-12-29
    • 1970-01-01
    • 2012-04-13
    • 2023-03-26
    • 2012-11-23
    • 1970-01-01
    • 2016-02-02
    • 1970-01-01
    相关资源
    最近更新 更多