簡體   English   中英

使用 C++ 處理運算符重載時出現意外的 output

[英]Unexpected output when dealing with operator overloading in C++ using

我正在嘗試通過“圓形”結構(基本上是二叉樹)來 go 。 每個圓都有一個 centerX、centerY、radius 和兩個葉節點。 這些葉子要么都是 null,要么都不是 null。 永遠不會有一個 null 和一個沒有 null。

我正在使用各種運算符重載函數。 我試圖用“,”運算符做一個,但實際上讓 function 命中時遇到了麻煩。

下面是相關代碼:

圈子.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);
};

圈子.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";

      //}
  }

測試.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 function 是應該為“,”操作激活代碼的地方。 function 在 circle.cpp 文件中稱為“Circle* reduce(set<Circle*>& circles)”。 在這個 function 中,以下代碼塊是對操作符函數進行一些調用的地方:

                  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;
                  }

使用“<”返回的 testBool 正常工作並觸發“bool Circle::operator<( Circle& other )”function,但“newC”圓圈分配不起作用和“Circle* Circle::operator” ,( Circle& other )" function 永遠不會被調用。 這讓我感到困惑,因為我以同樣的方式稱呼它們。

關於如何正確調用“,”圓圈運算符的任何想法?

運算符,優先級最低: https://en.cppreference.com/w/cpp/language/operator_precedence

由於 operator =實際上具有更高的優先級,因此問題行的效果更接近於:

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

但這不會觸發重載,因為左手現在是指針。

為了達到預期的效果,您可能需要在這對周圍放置大括號:

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

Marc 的答案是正確的:但是我建議您應該尋找的解決方案是不要重載operator, . 我還建議您不要為 class 重載operator<operator() ,並且不要為ostream class 重載operator/

在編寫代碼時,您應該問自己的第一個問題是“我的代碼試圖做什么?” 過度使用運算符重載通常會混淆代碼背后的想法,除非非常謹慎地使用,例如即使您的operator< function 它比較圓圈的面積也不會立即明顯。 operator()也很混亂——我知道你可能還沒有實現它,但看起來你正准備制作一個 function 來構建一個新的圓圈; 對於閱讀它並且必須猜測Circle c(x,y,r)和隨后的c(x1,y1)之間的區別的任何人來說,這不會是直觀的。

ostream class 的重載運算符是一個約定: <<將事物“流”到 class 和>>從 class 流事物。 嘗試閱讀具有ostream / object的代碼將導致(幾乎)任何查看它的人都進行雙重檢查。

您已經遇到的另一個問題是運算符具有優先級,這可能會導致奇怪的效果。 通過 function 調用,您知道操作數不會神奇地消失在附近不同 function 的操作數中。

這不是對你個人的咆哮,我一直認為“如果我自己重載 XYZ 操作符會更好看”,因為我相信這里的很多人也有,但退后一步並意識到它實際上在編寫代碼時,讓其他人更難閱讀代碼非常重要——尤其是 C++,它還有許多其他有趣的方式讓我們絆倒。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM