使用 C++ 处理运算符重载时出现意外输出
Unexpected output when dealing with operator overloading in C++ using
我正在尝试遍历“圆”结构(基本上是二叉树)。每个圆都有一个 centerX、centerY、radius 和两个叶节点。这些叶子要么都为空,要么都不为空。永远不会有一个null和一个not null。
我正在使用各种运算符重载函数。我正在尝试使用“,”运算符来执行此操作,但我在实际调用该函数时遇到了问题。
相关代码如下:
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;
}
使用“<”返回的 testBool 可以正常工作并触发“bool Circle::operator<( Circle& other )”函数,但“newC”圆赋值不起作用,“ Circle* Circle::operator,( Circle& other )" 函数永远不会被调用。这让我很困惑,因为我用同样的方式称呼它们。
关于如何正确调用“,”圆运算符的任何想法?
运算符 ,
的优先级最低,因此是最差的运算符,以这种方式使用:https://en.cppreference.com/w/cpp/language/operator_precedence
由于运算符 =
实际上具有更高的优先级,问题行的效果更接近于:
(Circle* newC = *current) , *current2;
但这不会触发过载,因为左手现在是指针。
为了达到预期的效果,您可能需要将大括号括起来:
Circle* newC = ( *current , *current2 );
Marc 的回答是正确的:但是我建议您寻找的解决方案是不要超载 operator,
。我还建议您也不要为 class 超载 operator<
或 operator()
,并且不要为 [=14] 超载 operator/
=] class.
在编写代码时,您应该问自己的第一个问题是“我的代码试图做什么?”过度使用运算符重载通常会混淆代码背后的想法,除非非常谨慎地使用,例如即使使用 operator<
函数,它也不会立即明显地比较圆的面积。 operator()
也很令人困惑——我知道你可能还没有实现它,但你似乎正准备制作一个构建新圈子的函数;这对任何阅读它的人来说都不是直观的,并且必须猜测 Circle c(x,y,r)
和随后的 c(x1,y1)
之间的区别是什么。
ostream
class 的重载运算符是一种约定:<<
流式处理 'to' class 和 >>
流式处理 'from' class。尝试阅读具有 ostream / object
的代码将导致(几乎)任何查看它的人都进行双重考虑。
您已经 运行 遇到的另一个问题是运算符具有优先级,这会导致奇怪的效果。通过函数调用,您知道操作数不会神奇地消失到附近不同函数的操作数中。
这不是针对你个人的咆哮,我一直认为 'this would look much nicer if I just overloaded XYZ operator' 我自己有罪,因为我相信这里的很多人也有,但退后一步,意识到它实际上使代码成为可能在编写代码时,让其他人更难阅读是非常重要的 - 特别是 C++,它有许多其他有趣的方式来绊倒我们。
我正在尝试遍历“圆”结构(基本上是二叉树)。每个圆都有一个 centerX、centerY、radius 和两个叶节点。这些叶子要么都为空,要么都不为空。永远不会有一个null和一个not null。
我正在使用各种运算符重载函数。我正在尝试使用“,”运算符来执行此操作,但我在实际调用该函数时遇到了问题。
相关代码如下:
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
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 )”函数,但“newC”圆赋值不起作用,“ Circle* Circle::operator,( Circle& other )" 函数永远不会被调用。这让我很困惑,因为我用同样的方式称呼它们。
关于如何正确调用“,”圆运算符的任何想法?
运算符 ,
的优先级最低,因此是最差的运算符,以这种方式使用:https://en.cppreference.com/w/cpp/language/operator_precedence
由于运算符 =
实际上具有更高的优先级,问题行的效果更接近于:
(Circle* newC = *current) , *current2;
但这不会触发过载,因为左手现在是指针。
为了达到预期的效果,您可能需要将大括号括起来:
Circle* newC = ( *current , *current2 );
Marc 的回答是正确的:但是我建议您寻找的解决方案是不要超载 operator,
。我还建议您也不要为 class 超载 operator<
或 operator()
,并且不要为 [=14] 超载 operator/
=] class.
在编写代码时,您应该问自己的第一个问题是“我的代码试图做什么?”过度使用运算符重载通常会混淆代码背后的想法,除非非常谨慎地使用,例如即使使用 operator<
函数,它也不会立即明显地比较圆的面积。 operator()
也很令人困惑——我知道你可能还没有实现它,但你似乎正准备制作一个构建新圈子的函数;这对任何阅读它的人来说都不是直观的,并且必须猜测 Circle c(x,y,r)
和随后的 c(x1,y1)
之间的区别是什么。
ostream
class 的重载运算符是一种约定:<<
流式处理 'to' class 和 >>
流式处理 'from' class。尝试阅读具有 ostream / object
的代码将导致(几乎)任何查看它的人都进行双重考虑。
您已经 运行 遇到的另一个问题是运算符具有优先级,这会导致奇怪的效果。通过函数调用,您知道操作数不会神奇地消失到附近不同函数的操作数中。
这不是针对你个人的咆哮,我一直认为 'this would look much nicer if I just overloaded XYZ operator' 我自己有罪,因为我相信这里的很多人也有,但退后一步,意识到它实际上使代码成为可能在编写代码时,让其他人更难阅读是非常重要的 - 特别是 C++,它有许多其他有趣的方式来绊倒我们。