【问题标题】:Unexpected output when dealing with operator overloading in C++ using使用 C++ 处理运算符重载时出现意外输出
【发布时间】:2022-01-05 20:39:39
【问题描述】:

我正在尝试通过“圆形”结构(基本上是二叉树)。每个圆都有一个 centerX、centerY、radius 和两个叶节点。这些叶子要么都是空的,要么都不是空的。永远不会有一个null和一个notnull。

我正在使用各种运算符重载函数。我正在尝试使用“,”运算符来做一个,但实际上我很难让该函数被命中。

下面是相关代码:

circle.h:

#include <set>
#include <iostream>

using namespace std;

class Circle {
 private:
  double centerX, centerY, radius;
  Circle* c1;
  Circle* c2;
  
 public:
  static const int PAGE_DIMENSION = 200;
  static const int DEFAULT_MAX_RADIUS = 15;
  
  Circle( double x, double y, double radius, Circle* r1,  Circle* r2 );
  Circle( double x, double y, double radius );
  Circle();
  
  int isLeaf() const;
  double getCenterX() const;
  double getCenterY() const;
  double area() const;
  double getRadius() const;
  Circle* getFirstSubcircle() const;
  Circle* getSecondSubcircle() const;
  
  bool operator<( Circle& other );
  Circle* operator()( double x_in, double y_in);
  Circle& operator=( Circle& rhs);
  Circle* operator,( Circle& other ); 
  double distance( Circle& rhs );

  // THESE FUNCTIONS ARE NOT CLASS MEMBERS
  // THEY ARE DEFINED OUTSIDE OF THE CLASS
  // BUT REQUIRE ACCESS TO PRIVATE FIELDS
  friend ostream& operator<<(ostream& osInput, Circle& circle);
  friend ostream& operator/(ostream& osInput, Circle& circle);
  friend Circle* reduce( set<Circle*>&  circles);
};

circle.cpp

#include <math.h>
#include <time.h>
#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <set>
#include <fstream>
#include "circle.h"


using namespace std;

       class CirclePair {
        public:
        Circle* c1;
        Circle* c2;
        double distance;

        CirclePair(Circle* c1, Circle* c2, double distance)
        {
            this->c1 = c1;
            this->c2 = c2;
            this->distance = distance;
        }
    };

  Circle::Circle( double x, double y, double radius, Circle* r1,  Circle* r2 )
  {
      centerX = x;
      centerY = y;
      this->radius = radius;
      c1 = r1;
      c2 = r2;
  }

  Circle::Circle( double x, double y, double radius )
  {
      centerX = x;
      centerY = y;
      this->radius = radius;
      c1 = NULL;
      c2 = NULL;
  }

  Circle::Circle()
  {
      unsigned seed = time(0);
      srand(seed);
      int randomX = rand() % (PAGE_DIMENSION + 1);
      int randomY = rand() % (PAGE_DIMENSION + 1);
      int randomRadius = rand() % DEFAULT_MAX_RADIUS + 1;
      centerX = randomX;
      centerY = randomY;
      radius = randomRadius;
  }

  int Circle::isLeaf() const
  {
      if (c1 == NULL && c2 == NULL) {
          return 1;
      }

      return 0;
  }

  double Circle::getCenterX() const
  {
      return centerX;
  }

  double Circle::getCenterY() const
  {
      return centerY;
  }

  double Circle::area() const
  {
      double pi = 3.14159265358979323846;

      return ( pi * (radius * radius));
  }

  double Circle::getRadius() const
  {
      return radius;
  }

  Circle* Circle::getFirstSubcircle() const
  {
      return c1;
  }

  Circle* Circle::getSecondSubcircle() const
  {
      return c2;
  }

  double Circle::distance( Circle& rhs )
  {
      double diffX = rhs.getCenterX() - getCenterX();
      double diffY = rhs.getCenterY() - getCenterY();
      return sqrt((diffX * diffX) + (diffY * diffY));
  }

  bool Circle::operator<( Circle& other )
  {
      cout << "Made it to operator <\n";
     return area() < other.area();
  }

  Circle* Circle::operator()( double x_in, double y_in)
  {
      Circle* c = new Circle();
      return c;
  }

  Circle& Circle::operator=( Circle& rhs)
  {
      cout << "Made it to operator =";
      Circle* c = new Circle();
      return *c;
  }

  Circle* Circle::operator,( Circle& other )
  {
      cout << "Made it to operator ,";
      double distanceBetween = distance(other);
      double c3Radius, c3CenterX, c3CenterY;
      Circle* c3;

      if (distanceBetween + getRadius() <= other.getRadius())
      {
          c3Radius = other.getRadius();
          c3CenterX = other.getCenterX();
          c3CenterY = other.getCenterY();
      }
      else 
      {
          double theta = 0.5 + ((other.getRadius() - getRadius()) / (2 * distanceBetween));
          c3Radius = (distanceBetween + getRadius() + other.getRadius()) / 2;
          c3CenterX = ((1 - theta) * getCenterX() + theta * other.getCenterX());
          c3CenterY = ((1 - theta) * getCenterY() + theta * other.getCenterY());
      }

      c3 = new Circle(c3CenterX, c3CenterY, c3Radius, this, &other);
      return c3;
  }

  ostream& operator<<(ostream& osInput, Circle& circle) 
  {
     osInput << "[ " << circle.centerX << ", " << circle.centerY << ", " << circle.radius << " ]\n";
     return osInput;
  }

  ostream& operator/(ostream& osInput, Circle& circle)
  {
      if (circle.isLeaf()) {
          osInput << " <circle cx=\"" << circle.centerX << "\" cy=\"" << circle.centerY <<"\" radius=\"" << circle.radius << "\" style=\"fill:blue;stroke:black;stroke-width:.05;fill-opacity:.1;stroke-opacity:.9\"/>\n";
      }
      else {
          osInput << " <circle cx=\"" << circle.centerX << "\" cy=\"" << circle.centerY <<"\" radius=\"" << circle.radius << "\" style=\"fill:yellow;stroke:black;stroke-width:.05;fill-opacity:.0;stroke-opacity:.5\"/>\n";
          Circle* firstCircle = circle.getFirstSubcircle();
          Circle* secondCircle = circle.getSecondSubcircle();
          osInput / *firstCircle;
          osInput / *secondCircle;
      }
  }

  Circle* reduce( set<Circle*>&  circles)
  {
      Circle* removeCirc1, removeCirc2;
      //while (circles.size() != 1)
      //{
          std::set<Circle*>::iterator circlesIterator = circles.begin();
          std::set<Circle*>::iterator circlesIterator2 = circles.begin();
          std::set<CirclePair*> setOfCirclePairs = {};
          while (circlesIterator != circles.end())
          {
              Circle *current = *circlesIterator;
              while (circlesIterator2 != circles.end())
              {
                  Circle *current2 = *circlesIterator2;
                  if (current != current2) 
                  {
                    CirclePair *currentPair = new CirclePair(current, current2, current->distance(*current2));
                    setOfCirclePairs.insert(currentPair);
                    bool testBool = *current2 < *current;
                    cout << testBool << "\n";
                    Circle* newC = *current , *current2;
                  }
                  circlesIterator2++;
              }
              circlesIterator++;
          }

          CirclePair* minDistancePair = NULL;
          std::set<CirclePair*>::iterator circlePairs = setOfCirclePairs.begin();
          while (circlePairs != setOfCirclePairs.end()) {
              CirclePair *currentCP = *circlePairs;
              if (minDistancePair == NULL)
              {
                  minDistancePair = currentCP;
              } 
              else
              {
                  if (currentCP->distance <= minDistancePair->distance)
                  {
                      minDistancePair = currentCP;
                  }
              } 
              cout << currentCP->c1->getCenterX() << " " << currentCP->c2->getCenterX() << " " << currentCP->distance << "\n";
              circlePairs++;
          }

          //find lowest distance pair
          cout << minDistancePair->distance << "\n";

      //}
  }

test.cpp:

#include <iostream>
#include <fstream>
#include <set>
#include <string>
#include <stdlib.h>
#include "circle.h"

using namespace std;

int main( int argc, char** argv ) {
    Circle* circ = new Circle();
    Circle* circ2_1 = new Circle(1, 2, 4);
    Circle* circ2_2 = new Circle(134, 55, 3);
    Circle* circ2 = new Circle(11, 21, 8, circ2_1, circ2_2);
    Circle* circ3 = new Circle(145, 123, 8);
    std::set<Circle*> setOfCircles { circ, circ2, circ3 };
    Circle* completedCircle = reduce(setOfCircles);    
}

在 tests.cpp 中调用的 reduce 函数是应该为“,”操作激活代码的地方。该函数在 circle.cpp 文件中称为“Circle* reduce(set& circles)”。在这个函数中,以下代码块是对操作符函数进行一些调用的地方:

                  if (current != current2) 
                  {
                    CirclePair *currentPair = new CirclePair(current, current2, current->distance(*current2));
                    setOfCirclePairs.insert(currentPair);
                    bool testBool = *current2 < *current;
                    cout << testBool << "\n";
                    Circle* newC = *current , *current2;
                  }

使用“

关于如何正确调用“,”圆圈运算符的任何想法?

【问题讨论】:

    标签: c++ operator-overloading


    【解决方案1】:

    运算符, 的优先级最低,因此是最差的运算符:https://en.cppreference.com/w/cpp/language/operator_precedence

    由于运算符=实际上具有更高的优先级,因此问题行的效果更接近于:

    (Circle* newC = *current) , *current2;
    

    但这不会触发重载,因为左手现在是一个指针。

    要达到预期的效果,您可能需要在这对周围放置大括号:

    Circle* newC = ( *current , *current2 );
    

    【讨论】:

    • 非常有意义。我对 c++ 很陌生(第一个项目),所以我很感激你说明它为什么不起作用。感谢您的解决方案!
    • 实际上我很惊讶你甚至可以重载运算符逗号,我以前不知道。每天你都会学到新东西!
    【解决方案2】:

    Marc 的回答是正确的:但是我建议您应该寻找的解决方案是不要超载operator,。我还将建议您也不要为您的班级重载 operator&lt;operator(),并且不要为 ostream 班级重载 operator/

    在编写代码时,您应该问自己的第一个问题是“我的代码试图做什么?”过度使用运算符重载通常会混淆代码背后的想法,除非非常谨慎地使用,例如即使使用您的 operator&lt; 函数,它也不会立即明显地比较圆圈的面积。 operator() 也很令人困惑——我知道你可能还没有实现它,但看起来你正准备制作一个构造一个新圆圈的函数;这对于阅读它并且必须猜测Circle c(x,y,r) 和随后的c(x1,y1) 之间的区别的人来说是不直观的。

    ostream 类的重载运算符是一个约定:&lt;&lt; 将事物“流向”类,&gt;&gt; 将事物“流向”类。尝试阅读具有ostream / object 的代码将导致(几乎)任何看到它的人都重复一遍。

    您已经遇到的另一个问题是运算符具有优先级,这可能会导致奇怪的效果。通过函数调用,您知道操作数不会神奇地消失在附近不同函数的操作数中。

    这不是对你个人的咆哮,我一直在想“如果我自己重载 XYZ 操作符会更好看”,因为我相信这里的很多人也有,但退后一步并意识到在编写代码时,它实际上使代码更难被其他人阅读,这一点非常重要——尤其是 C++,它有很多其他有趣的方式让我们绊倒。

    【讨论】:

    • 我很欣赏你的文章,这很有意义!这个问题实际上与我必须为学校做的一个项目有关。 Circle.h 实际上是给我们的,不能以任何方式更改。
    猜你喜欢
    • 2022-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-21
    • 2021-09-28
    • 2021-07-01
    • 1970-01-01
    • 2020-07-20
    相关资源
    最近更新 更多