C++ How to I replace this if...else statement?

c++, polymorphism

Solution

The standard solution for this problem, especially given your constraints regarding dependencies, is to use the Visitor Pattern.

Here's how Visitor Pattern would work in your case:

- You need an abstract `ShapeVisitor` class. It has an abstract `Visit` method for each concrete subclass of Shape. eg: `Visit(Circle*)`, `Visit(Square*)`, etc.

- Shape has an abstract `AcceptVisitor(ShapeVisitor*)` method.

- Each Shape subclass implements `AcceptVisitor` as just calling `visitor->Visit(this)`

- Each `CAD` class is a (or has-a, up to you) a `ShapeVisitor`. The `Visit` methods do the appropriate drawing for the specific type of `Shape`. No conditional or casting required.

Here's a modified version of your code that uses Visitor Pattern in a pretty low-impact way:

class Circle;
class Square;
class ShapeVisitor
{
    virtual void Visit(Circle *circle) = 0;
    virtual void Visit(Square *square) = 0;
}

class Shape
{
    virtual void AcceptVisitor(ShapeVisitor *visitor) = 0;
}


class Circle : public Shape
{
    // some special members/methods

    virtual void AcceptVisitor(ShapeVisitor *visitor)
    {
        visitor->Visit(this);
    }
}

class Square : public Shape
{
    // some special members/methods

    virtual void AcceptVisitor(ShapeVisitor *visitor)
    {
        visitor->Visit(this);
    }
}

class CAD : public ShapeVisitor
{
    virtual DrawCircle(Circle *circle) = 0;
    virtual DrawSquare(Square *square) = 0;

    virtual void Visit(Circle *circle) {
        DrawCircle(circle);
    }

    virtual void Visit(Square *square) {
        DrawSquare(square);
    }
}

class SWX : public CAD
{
    virtual DrawCircle(Circle *circle){// do some stuff that draws circle on SWX system}

}

class PRO : public CAD
{
    virtual DrawCircle(Circle * circle){// do some stuff that draws circle on PRO system}
}

int main()
{
    Circle * circle = new Circle();
    Square * sq = new Square;

    vector<Shape*> shapes;
    shapes.push_back(circle);
    shapes.push_back(sq);

    SWX * swx = new SWX();

    for( int i = 0 ; i < shapes.size() ; ++i )
    {
        shapes[i]->AcceptVisitor(SWX);
    }
}

In this code I've opted for making `CAD` actually a subclass of `ShapeVisitor`. Also, since you've already got virtual methods in `CAD` to do the drawing, I implemented the `Visit` methods there (once), rather than once in each subclass. Once you switch clients over to the using `AcceptVisitor` instead of calling the Draw* methods directly you could make those methods protected, and then eventually move the implementation of the `Visit` methods down to the subclasses (that is: refactor to remove the extra level of indirection caused by having `Visit(Foo*)` call `DrawFoo(Foo*)`).

Problem

I have the following C++ code (simplified version): ``` class Shape { bool isCircle = false; bool isSquare = false; } class Circle : public Shape { // some special members/methods } class Square : public Shape { // some special members/methods } class CAD { virtual DrawCircle(Circle * circle) = 0; } class SWX : public CAD { virtual DrawCircle(Circle * circle){// do some stuff that draws circle on SWX system} } class PRO : public CAD { virtual DrawCircle(Circle * circle){// do some stuff that draws circle on PRO system} } int main() { Circle * circle = new Circle(); circle->isCircle = true; Square * sq = new Square; sq->isSquare = true; vector<Shape*> shapes; shapes.push_back(circle); shapes.push_back(sq); SWX * swx = new SWX(); for( int i = 0 ; i < shapes.size() ; ++i ) { if( shapes[i]->isCircle ) { SWX->DrawCircle((Circle*)(shapes[i])); } else if( shapes[i]->isSquare ) { SWX->DrawSquare((Square*)(shapes[i])); } } ``` I wish to remove the need for if...else (if at all possible within the constraints stated below). My constraints right now are: - The CAD and derived classes are ginormous classes with various external dependencies. - The CAD classes cannot be merged with the Shape and derived classes (that would have been ideal, since then I can use polymorphism to solve my problem), since other projects/classes depend on the Shape classes and cannot depend on the CAD classes. - There are more than a dozen Shape-derived classes with a half dozen CAD-derived classes and this if...else is happening in numerous locations - so it would help if any solution is simple to understand (easier to convince my teammates to change legacy code). Any suggestions/comments/solution you have would be most welcome.

Original source