-1

I am trying to implement comparison between different subclasses of the same base class. The comparison should return false if the two instances are of different subclass or return the actual comparison result if they are of the same subclass.

Check the last line in function main: although I have declared equalTo as virtual, only the equalTo method of the base class is called. What is my mistake?

Thanks in advance.

#include <iostream>
#include <fstream>
#include <cmath>
#include <limits>
#include <sstream>
#include <stdexcept>
#include <algorithm>

using namespace std;

bool fileInput = false, fileOutput = false;

class Point
{
public:
    double x,y;
    Point(){};
    Point(double x1, double y1) {
        x=x1;
        y=y1;
    }
    bool operator==(Point other) const
    {
        return (abs(x - other.x) < numeric_limits<double>::epsilon()) and (abs(y - other.y) < numeric_limits<double>::epsilon());
    }
};

class Shape
{
protected:
    virtual double area() const
    {
        return 0;
    }
    virtual void print(std::ostream& os) const {}
    virtual void read(std::istream& is) {}
public:
    bool compare(Shape* other) {
        return area() < other->area();
    }
    virtual bool equalTo(Shape other) const {
        cout << "original";
        return false;
    }
    friend std::ostream& operator<<(std::ostream &strm, const Shape &t)
    {
        t.print(strm);
        return strm;
    }
    friend std::istream& operator>>(std::istream &strm, Shape &t)
    {
        t.read(strm);
        return strm;
    }
};

class Circle : public Shape
{
    Point c;
    double r;
    double area() const
    {
        return M_PI * r * r;
    }
    void print(std::ostream &strm) const
    {
        strm << "Circle. Center coordinates: (" << c.x << "," << c.y << "). Radius: " << r << ". Area: " << area();
    }
    void read(std::istream &strm)
    {
        if (!fileInput) cout << "Enter Circle\nCenter: ";
        strm >> c.x >> c.y;
        if (!fileInput) cout << "Radius: ";
        strm >> r;
        if (r<0)
            throw std::invalid_argument( "The radius cannot be negative." );
    }
public:
    Circle() {}
    Circle(Point x, double y)
    {
        c = x;
        r = y;
    }
    bool equalTo(Shape other1) const
    {
        Circle* other = dynamic_cast<Circle*>(&other1);
        if (other == 0) return false;
        return (c == other->c) and (abs(r - other->r)<numeric_limits<double>::epsilon());
    }
};

class Hexagon : public Shape
{
    Point c;
    double r;
    double area() const
    {
        return 1.5 * sqrt(3) * r * r;
    }
    void print(std::ostream &strm) const
    {
        strm << "Hexagon. Center coordinates: (" << c.x << "," << c.y << "). Circumcircle radius: " << r << ". Area: " << area();
    }
    void read(std::istream &strm)
    {
        if (!fileInput) cout << "Enter Hexagon\nCenter: ";
        strm >> c.x >> c.y;
        if (!fileInput) cout << "Circumcircle radius: ";
        strm >> r;
        if (r<0)
            throw std::invalid_argument( "The circumcircle radius cannot be negative." );
    }
public:
    Hexagon() {}
    Hexagon(Point x, double y)
    {
        c = x;
        r = y;
    }
    bool equalTo(Shape other1) const
    {
        Hexagon* other = dynamic_cast<Hexagon*>(&other1);
        if (other == 0) return false;
        return (c == other->c) and (abs(r - other->r)<numeric_limits<double>::epsilon());
    }
};

int main()
{
    Shape c1 = Circle(Point(0,0), 3);
    Shape c2 = Circle(Point(0,0), 3);
    Shape c3 = Hexagon(Point(0,0), 3);
    cout << "circles: " << c1.equalTo(c2) << endl << "diff: " << c1.equalTo(c3) << endl;
}
Jonathan Eustace
  • 2,469
  • 12
  • 31
  • 54
babis
  • 228
  • 1
  • 9
  • 2
    possible duplicate of [What is object slicing?](http://stackoverflow.com/questions/274626/what-is-object-slicing) – sashoalm Mar 12 '15 at 12:01

2 Answers2

3

This is slicing, when you assign objects to object of type Shape - object was sliced to Shape. Use pointers, or may be references.

Circle p1(Point(0, 0), 3);
Circle p2(Point(0, 0), 3);
Hexagon h1(Point(0, 0), 3);
Shape& c1 = p1;
Shape& c2 = p2;
Shape& c3 = h1;
ForEveR
  • 55,233
  • 2
  • 119
  • 133
  • thanks! can you please also explain how I can create an array of `Shape`s while keeping the actual class of all objects? – babis Mar 13 '15 at 09:11
1

When you copy-construct a Shape out of a derived class, the object will be sliced so that only the Shape part of it is preserved. Then when you call equalTo, the function is statically bound.

In order to call the derived versions, make c1 and friends into Shape&.

TartanLlama
  • 63,752
  • 13
  • 157
  • 193