Search code examples
c++inheritanceoperator-overloadingostreamcomparison-operators

C++ inheritance of overloading of comparison and output operators


I have some C++ classes with geometric figures where I need to overload the comparison operators (such as >, <, =, etc..) and the output operator << in a way that every time I need to print or compare any instance of these classes, I refer to the value of their area (which I get using getArea()).

I tried to place those operator overloads in the parent class GeometricShape but I got all kinds of compiler errors which made no much sense to me.

If I place the operator overloads in each child class it works fine, but it's quite ugly and not ideal (a lot of code repetition).

How can I remove this code repetition and move the operators overloading to the parent class?

using namespace std;

#include <iostream>
#include <stdlib.h>
#include <math.h>

class GeometricShape
{
    public:

    double getArea();
};

class Poligon : public GeometricShape
{
    protected:

    double base;
    double height;

    public:

    Poligon(double base, double height) : base(base), height(height) {}
    Poligon(float base, float height) : Poligon(double(base), double(height)) {}
    Poligon(int base, int height) : Poligon(double(base), double(height)) {}

    double getBase()
    {
        return this->base;
    }

    double getHeight()
    {
        return this->height;
    }

    void setBase(double b)
    {
        this->base = b;
    }

    void setHeight(double a)
    {
        this->height = a;
    }
};


class Rectangle : public Poligon
{
    public:

    Rectangle(double base, double height) : Poligon(base, height) {}
    Rectangle(float base, float height) : Poligon(base, height) {}
    Rectangle(int base, int height) : Poligon(base, height) {}

    double getArea()
    {
        return base * height;
    }

    // HOW TO MOVE THIS CODE INTO GeometricShape and reuse it???
    friend ostream& operator<<(ostream& out, Rectangle &obj)
    {
        out << obj.getArea();
        return out;
    }
    friend bool operator==(Rectangle &obj1, Rectangle &obj2)
    {
        return obj1.getArea() == obj2.getArea();
    }
    friend bool operator>(Rectangle &obj1, Rectangle &obj2)
    {
        return obj1.getArea() > obj2.getArea();
    }
    friend bool operator<(Rectangle &obj1, Rectangle &obj2)
    {
        return obj1.getArea() < obj2.getArea();
    }
    friend bool operator <= (Rectangle &obj1, Rectangle &obj2)
    {
        return obj1.getArea() <= obj2.getArea();
    }
    friend bool operator >= (Rectangle &obj1, Rectangle &obj2)
    {
        return obj1.getArea() >= obj2.getArea();
    }
};

class Triangle : public Poligon
{
    public:

    Triangle(double base, double height) : Poligon(base, height) {}
    Triangle(float base, float height) : Poligon(base, height) {}
    Triangle(int base, int height) : Poligon(base, height) {}

    double getArea()
    {
        return (base * height)/2;
    }
    
    // HOW TO MOVE THIS CODE INTO GeometricShape and reuse it???
    friend ostream& operator<<(ostream& out, Triangle &obj)
    {
        out << obj.getArea();
        return out;
    }
    friend bool operator==(Triangle &obj1, Triangle &obj2)
    {
        return obj1.getArea() == obj2.getArea();
    }
    friend bool operator>(Triangle &obj1, Triangle &obj2)
    {
        return obj1.getArea() > obj2.getArea();
    }
    friend bool operator<(Triangle &obj1, Triangle &obj2)
    {
        return obj1.getArea() < obj2.getArea();
    }
    friend bool operator <= (Triangle &obj1, Triangle &obj2)
    {
        return obj1.getArea() <= obj2.getArea();
    }
    friend bool operator >= (Triangle &obj1, Triangle &obj2)
    {
        return obj1.getArea() >= obj2.getArea();
    }
};

class Circle : public GeometricShape
{
    double radius;

    public:

    Circle(double radius) : radius(radius) {}

    double getArea()
    {
        return (radius * radius) * M_PI;
    }

    double getRadius()
    {
        return this->radius;
    }

    void setRadius(double r)
    {
        this->radius = r;
    }

    // HOW TO MOVE THIS CODE INTO GeometricShape and reuse it???
    friend ostream& operator<<(ostream& out, Circle &obj)
    {
        out << obj.getArea();
        return out;
    }
    friend bool operator==(Circle &obj1, Circle &obj2)
    {
        return obj1.getArea() == obj2.getArea();
    }
    friend bool operator>(Circle &obj1, Circle &obj2)
    {
        return obj1.getArea() > obj2.getArea();
    }
    friend bool operator<(Circle &obj1, Circle &obj2)
    {
        return obj1.getArea() < obj2.getArea();
    }
    friend bool operator <= (Circle &obj1, Circle &obj2)
    {
        return obj1.getArea() <= obj2.getArea();
    }
    friend bool operator >= (Circle &obj1, Circle &obj2)
    {
        return obj1.getArea() >= obj2.getArea();
    }
};


Solution

  • There are quite a few things that need to be fixed with this code.

    An external freestanding operator< should give no compilation errors:

    bool operator<(GeometricShape& s1, GeometricShape& s2) {
        return s1.getArea() < s2.getArea();
    }
    
    1. You should mark both the arguments to operator< as const. This would require marking all the instances of getArea const as well.
    2. getArea should be marked virtual in GeometricShape. All the subclasses should mark the method with override as well. Otherwise, getArea from GeometricShape will be called.
    3. In Geometric shape you should make the getArea() function pure virtual.
    4. To make sure that the objects of derived classes have the correct destructors called on them, you should mark the destructor in GeometricShape as virtual.

    This would make your method signature look something like:

    For GeometricShape:

    virtual double getArea() const = 0;
    

    For derived classes:

    double getArea() const override;
    

    EDIT: There were quite a lot of suggestions in the comments on how to improve this piece of code. I have tried my best to summarise them here.