-2

In C++, I have two separate base classes, each of whose derived classes are somewhat coupled. Here's an example for the kind of thing I'd like to do:

First define a set of classes, e.g.,:

class Shape
     {
     public:
        double area;
        double diameter;
     };

class Rectangle : public Shape
     {
     public:
        double width;
        double height;
     };

class Circle : public Shape
     {
     public:
        double radius;
     };

The second set of classes then pertains to operations being performed on this first set of classes, something like this:

class Calculator
    {
    public:
        static Calculator *create_calculator(shape *shape,const char *shape_type); // the factory
        virtual void calculate()=0; // the actual calculation
     };


class area_circles : public Calculator
    {
    class circles *circle;
    public 
    area_circles(circles *circle)
        {
        this->circle = circle;
        }
    void calculate()
        {
        this->area = PI*pow(circle->radius,2);      
        }
    }


class area_rectangles : public Calculator
    {
    class rectangles *rectangle;
    public 
    area_rectangles(rectangles *rectangle)
        {
        this->rectangle = rectangle;
        }
    double calculate()
        {
        this->area = rectangle->height * rectangle->width;
        }
    }

Calculator *Calculator::create_calculator(shape *shape, const char *shape_type)
    {
    if (shape_type=="circle")
        return new area_circles(shape);

    if (shape_type=="rectangle")
        return new area_rectangles(shape);
    }

Then, the idea would be to call all this using something like:

rectangles *my_rectangle;
Calculator *area_calculator;
area_calculator = area_calculator->create_calculator(my_rectangle, "rectangle");
area_calculator->calculate();

However, this doesn't compile and I get an error (quite sensibly) pointing out how the Shape class has no member "width", and that "a value of type "shape *" cannot be assigned an entity of type "rectangles". The error's pretty clear on why this code isn't working.

Would anyone know how to get the code here to do what I'm trying to do?

From a design perspective, I recognize that part of the problem is that the derived classes end up being coupled, so maybe there is a better way to try to decouple the calculator class from the shape class. But I'd like to at least try out this approach for a while as well in my implementation, and for that I need the code to compile.

user1790399
  • 220
  • 2
  • 11
  • Why don't you use `struct` when that's what you describe? BTW: Why both `diameter` and `radius`? Also, `area` and `diameter` nearly allow you to derive `width` and `height`, you only need one bit to decide which is (potentially) bigger. – Deduplicator Oct 28 '14 at 00:50
  • Your code does not agree with your description. Your first chunk of code declares "Rectangle" and "Circle" classes. Your second chunk of code references "rectangles" and "circles" classes. Your third chunk of code that you claim does not compile because of errors referring to "width" does not appear to have any references to "width". You need to reorganize this question, and make it quite clear exactly what your problem is. – Sam Varshavchik Oct 28 '14 at 00:53
  • 3
    Is there a reason to decouple area calculations from shapes to begin with, as opposed to just having area calculation be a virtual method implemented by each shape subclass? – paisanco Oct 28 '14 at 00:58
  • You are passing a rectangle pointer to a method that takes a shape pointer: `area_calculator = area_calculator->create_calculator(my_rectangle, "rectangle");` – fhsilva Oct 28 '14 at 01:04
  • By the way, `diameter` property usually does not apply to rectangles, so it should not be in the `Shapes` parent class. – Thomas Matthews Oct 28 '14 at 01:08
  • One of your problems is that you've defined `Calculator::create_calculator` before the classes it tries to use: `area_circles` and `area_rectangles`... move it after those class definitions. – Tony Delroy Oct 28 '14 at 01:16

1 Answers1

0

I am not entirely sure what you are trying to achieve here but I think the more usual approach to it is something like this:

class Shape
{
public:
    virtual ~Shape() {}

    // concrete classes must implement this function
    virtual double get_area() const = 0; 
};

class Circle
: public Shape
{
    double diameter;

public:
    Circle(double diameter): diameter(diameter) {}

    virtual double get_area() const
    {
        return M_PI * diameter * diameter / 4;
    }
};

class Rectangle
: public Shape
{
    double width;
    double height;

public:
    Rectangle(double width, double height): width(width), height(height) {}

    virtual double get_area() const
    {
        return width * height;
    }
};

int main()
{
    Circle c(2);
    Rectangle r(20, 40);

    // use Shape references (or pointers) to invoke polymorphic behaviour
    Shape& cs = c;
    Shape& rs = r;

    std::cout << "Area of circle   : " << cs.get_area() << '\n';
    std::cout << "Area of rectangle: " << rs.get_area() << '\n';
}
Galik
  • 47,303
  • 4
  • 80
  • 117