4

For a lab, I had to overload the + operator to add objects from the same class and the == operator to compare objects from two different classes. The function to overload the == operator is giving me so much trouble (likely because I'm using it to compare the object areas of different classes). I've looked for a solution relentlessly, and I've tried all the suggestions found without success, so I'm forced to ask using my specific code:

// OBJECTIVES:
// Add areas of 2 circles
// Add areas of 2 rectangles
// Compare areas of a circle and a rectangle

#include <iostream>
using namespace std;

// **********************Header*********************
class circle
{
    friend bool operator==(const circle& ,
                           const circle&);
    friend circle operator+(const circle& , 
                            const circle&);
public:
    double radius, area;
    void calcArea();
};

class rect
{
    friend bool operator==(const rect& , 
                           const rect&);
    friend rect operator+(const rect& , 
                          const rect&);
public:
    double length, width, area;
    void calcArea();
};

void displayMenu();
// **************************************************

// **********************Program*********************
int main()
{
    int selection; // variable for menu selection

    circle firstCircle; // objects from circle class
    circle secondCircle;

    rect firstRect; // objects from rect class
    rect secondRect;

    do {
        displayMenu();
        cin >> selection;
        cout << endl;

        if (selection == 1) // add area of 2 circles
        {
            firstCircle.calcArea();
            secondCircle.calcArea();
            circle thirdCircle = firstCircle + secondCircle;

            cout << "The sum of your two circles is: " ;
            cout << thirdCircle.area;
            cout << endl;
        }

        else if (selection == 2) // add area of 2 rectangles
        {
            firstRect.calcArea();
            secondRect.calcArea();
            rect thirdRect = firstRect + secondRect;

            cout << "The sum of your two rectangles is: " ;
            cout << thirdRect.area;
            cout << endl;

        }

        else if (selection == 3) // compare areas of a circle and a rectangle
        {
            firstCircle.calcArea();
            firstRect.calcArea();

            if (firstCircle.area == firstRect.area)
            {
                cout << "The area of your circle is equal to that of your rectangle." << endl;
            }
            else
            {
                cout << "The area of your circle is not equal to that of your rectangle." << endl;
            }
        }

        else if (selection == 4) // exit program
        {
            return 0;
        }

        else
        {
            cout << "Please enter a valid selection.";
            cout << endl;
            continue;
        }
    } while (1);

    return 0;
}
// **************************************************

// ******************Implementation******************
void circle::calcArea() // compute circle area
{
    cout << "Enter a radius: ";
    cin >> radius;

    area = 3.14159265359 * radius * radius;
}

void rect::calcArea() // compute rectangle area
{
    cout << "Enter a length: ";
    cin >> length;
    cout << "Enter a width: ";
    cin >> width;

    area = length * width;
}

bool operator==(const circle& firstCircle, // compare areas of objects
                const rect& firstRect)  // from different classes
{
    return (firstCircle.area == firstRect.area && 
            firstCircle.area == firstRect.area);
}

circle operator+ (const circle& firstCircle, // overload + for circle class
                    const circle& secondCircle)
{
    circle circleSum;

    circleSum.radius = firstCircle.radius + secondCircle.radius;
    circleSum.area = firstCircle.area + secondCircle.area;

    return circleSum;
}

rect operator+ (const rect& firstRect, // overload + for rect class
                    const rect& secondRect)
{
    rect rectSum;

    rectSum.length = firstRect.length + secondRect.length;
    rectSum.width = firstRect.width + secondRect.width;
    rectSum.area = firstRect.area + secondRect.area;

    return rectSum;
}

void displayMenu() // menu options
{
    cout << endl;
    cout << "What would you like to do?" << endl;
    cout << "1. Add the area of 2 circles."<< endl;
    cout << "2. Add the area of 2 rectangles."<< endl;
    cout << "3. Compare the area of a circle and a rectangle."<< endl;
    cout << "4. Exit.";
}
// **************************************************

Right now, I'm not using the overloaded == to compare the rectangle and circle areas because then I get a lot of compiler errors. Any help you guys can offer me to be able to change firstCircle.area == firstRect.area to firstCircle == firstRect would be so greatly appreciated.

Sergey
  • 7,985
  • 4
  • 48
  • 80
Keli
  • 41
  • 1
  • 2
  • Looks like at least one problem is that the overloaded == operator is used before it is declared in your code. Add a declaration above the main (you can still define it after the main functions code block). – Timothy Murphy Oct 30 '18 at 03:53
  • I would suggest that you need to think about inheritance. Circle and Rectangle are both shapes with area (hint make Circle and Rectangle inherit from a class Shape. – samuelnj Oct 30 '18 at 03:56
  • Helpful reading: [What are the basic rules and idioms for operator overloading?](https://stackoverflow.com/questions/4421706/what-are-the-basic-rules-and-idioms-for-operator-overloading) – user4581301 Oct 30 '18 at 04:02
  • Suggestion: When asking a question on stack overflow, back up your program and then remove everything that's not related to the question. If the question isn't about the menu, the menus goes. If the question isn't about `operator +`, `+` goes. all you want is a `main` and the stuff you're having problems with. Who knows, without all the extra noise you might figure out what went wrong yourself! – user4581301 Oct 30 '18 at 04:05
  • Tactical point: why does a method named `calcArea` take input? It sounds like it should be calculating the area. A function should do one thing and only one thing. If it does two things, it is actually less useful. You can't calculate the area of an existing circle, for example. You'd have to feed in the radius again, and that's kind-of silly. – user4581301 Oct 30 '18 at 04:09

2 Answers2

5

There is a number of approaches to write a comparison operator you want. The simplest way, without interventing your class code, is just to implement a couple of nonmember operators:

bool operator==(const circle& c, const rect& r) { return r.area == c.area; }
bool operator==(const rect& r, const circle& c) { return c.area == r.area; }

You might put them in you source file above the main function, or to a separate header file. Note that they don't need to be friends of circle and rect, as area member is public.

Another way is to write member functions, but first we need to fix your existing comparison operators:

class circle
{
public:
    bool operator==(const circle& other) const { return area == other.area; }

    // ...skipped...
};

How and why is it different from your version?

  1. It's a member function which compares this to other, taking only one argument.
  2. It's public to be called from outside of circle class
  3. It's const-qualified, because it needs only a lookup of class data without modifications.

Also const qualifier allows you to compare const objects like this:

const circle c1 = getSomeCircle();
const circle& c2 = otherCircle;
c1 == c2; // Note: statement has no effect, despite it's syntax is correct.
c2 == c1;

Non-const-qualified comparison would fail to compile. All in all, this is the most idiomatic way to write comparison operators in C++.

Finaly, let's add circle to rect comparison:

class rect;

class circle
{
public:
    bool operator==(const circle& other) const { return area == other.area; }
    bool operator==(const rect&) const;

    // ...skipped...
};

class circle { /* class definition skipped */ };

bool operator==(const rect& r) const { return area == r.area; }

Here first we declared the rect class. When class is declared but not defined (which is forward declaration), we can use pointers ant references to it's instances, but not instances themselves. One of the reasons we can't use instances is that class size is unknown before it's definition.

Then we declare member operator== accepting a reference to forward-declared class, and finally after rect definition we can implement the operator.

rect to circle comparison may be implemented all the same way.

Sergey
  • 7,985
  • 4
  • 48
  • 80
  • 1
    Worth noting that comparing `double`s for equality can get real nasty [because doubles and double arithmetic is imprecise](https://stackoverflow.com/questions/588004/is-floating-point-math-broken). Usually you need [an epsilon](https://en.wikipedia.org/wiki/Machine_epsilon). – user4581301 Oct 30 '18 at 04:34
  • @user4581301 Surely. I just skipped this topic in the answer as it's already large enough for a C++ beginner. – Sergey Oct 30 '18 at 04:41
  • No worries. The note is more for them and those who follow because it is a really nasty surprise when you're not expecting it. And no one new ever does. – user4581301 Oct 30 '18 at 04:43
0

Operator overloading can be overloaded like below.

#include <iostream>
using namespace std;

class rect;

class circle
{
    friend bool operator==(const circle&,
        const circle&);
    //friend circle operator+(const circle&,
    //  const circle&);
public:
    double radius, area;
    //void calcArea();
public:
    friend bool operator == (const circle&, const rect&);
    double getArea()const { return area; }
};

class rect
{
    friend bool operator==(const rect&,
        const rect&);
    //friend rect operator+(const rect&,
    //  const rect&);
public:
    double length, width, area;
    //void calcArea();
public:
    friend bool operator == (const rect&, const circle&);
    double getArea() const{ return area; }
};

int main(int argc, char *argv[]) {
    circle c;
    rect r;
    if (c == r) {
        cout << "It was a miracle a random circle is equal to a random rectangle in size!!!" << endl;
    }
    return 0;
}

bool operator == (const circle &c1, const circle &c2) {
    return c1.getArea() == c2.getArea();
}

bool operator == (const rect &r1, const rect &r2) {
    return r1.getArea() == r2.getArea();
}

bool operator == (const circle &c, const rect &r) {
    return c.getArea() == r.getArea();
}

bool operator == (const rect &r, const circle &c) {
    return c.getArea() == r.getArea();
}
CPMM
  • 76
  • 7
  • Note: if `circle` and `rect` derive from, say, `shape`, and `shape` has a `getArea` method then you can `bool operator == (const shape &a, const shape &b) { return a.getArea() == b.getArea(); }` – user4581301 Oct 30 '18 at 04:15