I am attempting to go through a "Circle" structure (basically a binary tree). Each circle has an centerX, centerY, radius, and two leaf nodes. These leaves will either both be null or both be not null. There will never be one null and one not null.
I am using a variety of operator overloading functions. I am attempting to do one with the "," operator but I am having trouble actually getting the function to hit.
Below is the relevant code:
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);
}
The reduce function that is called within tests.cpp is where the code should be getting activated for the "," operation. The function is called "Circle* reduce( set<Circle*>& circles)" within the circle.cpp file. In this function, the following chunk of code is where some calls are made to the operator functions:
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;
}
The testBool that is returned from using the "<" works correctly and triggers the "bool Circle::operator<( Circle& other )" function, but the "newC" circle assignment that is not working and the "Circle* Circle::operator,( Circle& other )" function is never being called. This confuses me as I am calling them both in the same fashion.
Any ideas on how to properly call the "," circle operator?
CodePudding user response:
Operator ,
has lowest precedence of all, and therefore is the worst operator to be used in this manner: https://en.cppreference.com/w/cpp/language/operator_precedence
Since operator =
actually has higher precedence, the effect of the problem line is closer to something like:
(Circle* newC = *current) , *current2;
But this won't trigger the overload as the left hand is now a pointer.
To achieve the desired effect you probably need to put braces around the pair:
Circle* newC = ( *current , *current2 );
CodePudding user response:
The answer by Marc is correct: however I am going to recommend that the solution you should be looking for is don't overload operator,
. I'm also going to recommend that you also don't overload operator<
or operator()
for your class, and that you don't overload operator/
for the ostream
class.
On of the first question you should ask yourself when writing code is "what does it look like my code is trying to do?" Excessive use of operator overloading generally obfuscates the idea behind the code unless used very sparingly, e.g. even with your operator<
function it isn't going to be immediately obvious that it compares the area of the circles. The operator()
is also very confusing - I know you probably haven't implemented it yet but it seems like your gearing up to make a function which constructs a new circle; this is not going to be intuitive to anyone who reads it and has to guess what the difference between Circle c(x,y,r)
and a subsequent c(x1,y1)
is.
Overloading operators for the ostream
class is a convention: <<
streams things 'to' the class and >>
streams things 'from' the class. Trying to read code which has ostream / object
is going to cause (almost) anyone who looks at it to do a double take.
Another problem, which you have already run into, is that operators have precedence which can lead to weird effects. With function calls, you know that the operands aren't going to magically disappear into operands of a different nearby function.
This is not a rant against you personally, and I have been guilty of thinking 'this would look much nicer if I just overloaded XYZ operator' myself as I am sure many people here have too, but taking a step back and realising that it actually makes the code much harder for other people to read is really important when writing code - especially C which has so many other interesting ways of tripping us up.