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.
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*)).
This is a classic case for DoubleDispatch, where you need to have a separate method for each possible (Shape, CAD) pair:
Nuke the isSquare/isCircle fields.
add virtual void DrawOn(CAD*) to the Shape interface.
Implement Circle::DrawOn(CAD*) (for example):
void Circle::DrawOn(CAD *c) {
c->DrawCircle(this);
}
This is the "trick" which allows a call like myCircle->DrawOn(mySWX) to call the correct method no matter the type of the Shape or the CAD.
You've got some rather wonky OO going on there, but at the very least DrawXxxx should just become Draw(). Circle, Square, and the other shapes would then define a Draw() method that provides an implementation for a virtual Draw method on Shape. Then you can just call Draw on any Shape and it will do the right thing.
The isXxxx booleans should go too. Classes know what they are and instanceof can tell you (though it shouldn't be necessary to check when you Draw since that will be a virtual method invocation).
Why not just SWX->Draw(shapes[i]);? You would need to add two Draw method with one that takes a Circle and one that takes a square?
This is pretty basic OO polymorphism. Circle and Square are specialized versions of shape. They should each know what specialized behavior is needed to deal with your cad classes.
class Shape
{
virtual void DrawWithCAD(CAD * cad) = 0;
}
class Circle : public Shape
{
virtual void DrawWithCAD(CAD * cad)
{
cad->DrawCircle(this);
}
}
class Square : public Shape
{
virtual void DrawWithCAD(CAD * cad)
{
cad->DrawSquare(this);
}
}
Then your main() loop would change to:
for( int i = 0 ; i < shapes.size() ; ++i )
{
shapes[i]->DrawWithCAD(swx);
}
Why not define a simple ICAD interface? Since CAD depends on Shape it does not increase complexity:
class Shape
{
Draw(ICAD* cad) = 0;
}
class Circle : public Shape
{
Draw(ICAD* cad)
{
ICAD->DrawCircle(self)
}
}
class Square : public Shape
{
Draw(ICAD* cad)
{
ICAD->DrawSquare(self)
}
}
DrawSquare(self) looks funny, but I don't know what the CAD classes do with the shape objects.
class ICAD
{
virtual DrawSquare(Square* square) = 0;
virtual DrawCircle(Circle * circle) = 0;
}
I assume class CAD has more than those abstract methods, which is why you don't couple it with Shape.
class CAD : public ICAD
{
// big CAD class...
}
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]->Draw(swx);
}
}
This may not be the ideal solution, but you could just provide an CAD::Draw member function and overload it to handle each different type of shape. Something like:
class CAD {
public:
virtual void Draw(const Circle& circle) = 0;
virtual void Draw(const Square& square) = 0;
};
Then you could just call Draw on any supported object without any if statements.
Write a several global Draw functions overloaded for each Shape... (DrawCircle and friends are virtual so we can use polymorphism for calls to CAD objects)
void Draw(CAD *cad, Circle *circle){
cad->DrawCircle(circle);
}
void Draw(CAD *cad, Square *square){
cad->DrawSquare(square);
}
Related
I'm having trouble to clearly visualize my idea in words. Below example may explain my thinking. I've two abstract class and two Derived class,
class Base1{
public:
virtual void f1() = 0;
std::string get(){ return "HelloWorld";}
};
class Derived1: public Base1{
public:
void f1() {}
void update (std::string& update){
**should call like** Base2::Derived2::update_data(this);}
};
=> and
class Base2{
public:
virtual void f2 () = 0;
};
class Derived2: public Base2{
public:
void f2() {}
void get (Base1& d1){ d1.Base1::get (); }
void update_data (Base1& d1){ d1.Base1::get (); }
};
=> the classes are called as
int main(){
Derived1 d1;
Derived2 d2;
d2.get (d1);
std::string hi = "hiWorld";
d1.update (hi);
return 0;
}
How can I achieve the **should call like** without passing the Base2 instance in d1.update ().
Another question is, what does it called, when each class objects knows other objects?
Thanks.
It seems like you need a technique called double-dispatch. C++ only directly supports single-dispatch - the behavior you get is only based on a single instance.
a->virtualFunction( params ); // exactly which implementation is called depends on the concrete type of a.
For double dispatch, (which does not exist), you would need something like
(a,b)->virtualFunction( params ); // where the call is based on both parameters.
There are some solutions to the problem. These require work where one type requires the knowledge of the other, but only that way round.
Consider a set of geometric shapes which we want to draw on surfaces.
class Surface;
class Drawable {
public:
virtual ~Drawable () {}
virtual void draw( Surface * ) = 0;
};
class Surface {
public:
virtual ~Surface () {}
// details ommitted.
}
class Rectangle : public Drawable {
};
class Circle : public Drawable {
}
// and some surfaces
class PrinterSurface : public Surface {
};
class PlotterSurface : public Surface {
};
The code we actually want to call, is dependent on both the surface and the shape.
To solve this, we choose one of the hierarchies which is most bounded, and tell the other hierarchy about the concrete instances of the type.
In this example, it is considered that more shapes and drawable objects will exist than technologies for rendering them.
So each drawable item will know how to draw on each of the surfaces.
class Drawable {
public:
virtual ~Drawable () {}
virtual void drawPrinter( Surface * ) = 0;
virtual void drawPlotter( Surface * ) = 0;
virtual void drawSurface( Surface * ) = 0;
};
class Surface {
public:
virtual ~Surface () {}
virtual void draw( Drawable * pDrawable ) = 0;
}
class PrinterSurface : public Surface {
void draw( Drawable * pDrawable ) {
pDrawable->drawPrinter( this );
}
};
Now a call to Surface->draw( Drawable *) will be bounced into a concrete implementation, where each Drawable understands how to render onto a device, but the devices have no knowledge of the gamut of Drawables
For further reading : wikipedia : double dispatch for a more full description.
and I would recommend the design patterns book wikipedia : design patterns
The design patterns give some idea of a vocabulary of design which make asking this form of question much easier.
Let's say I want to implement three different classes: Square, ColoredSquare, TexturedSquare.
Since ColoredSquare is a Square with a color and TexturedSquare is a ColoredSquare with a texture, my first thought was to have them all deriving from each other:
class Square {
Square::Square(position)
: position_(position)
{
}
}
class ColoredSquare : public Square {
ColoredSquare::ColoredSquare(position, color)
: Square(position), color_(color)
{
}
}
class TexturedSquare: public ColoredSquare {
TexturedSquare::TexturedSquare(position, color, texture)
: ColoredSquare(position, color), texture_(texture)
{
}
};
However, I remembered reading that having too much inheritance depth was bad practice (and that generally, classes should only be deriving from abstract classes).
So I thought about switching to a single class:
class Square {
Square::Square(glm::vec3 position)
: position_(position), type_(SquareType::Basic)
{
}
Square::Square(glm::vec3 position, glm::vec4 color)
: position_(position), color_(color), type_(SquareType::Colored)
{
}
Square::Square(glm::vec3 position, glm::vec4 color, glm::vec2 texture)
: position_(position), color_(color), texture_(texture), type_(SquareType::Textured)
{
}
};
Now, while I find it acceptable for now, I'm thinking it might be unpractical in the future (I won't be able to use polymorphism) and I'm also wondering if this is in breach of the Single Responsability Principle.
What would be the best way to implement this hierarchy structure in a clean, extensive way?
I don't think there's one correct answer to this question, but there are other approaches available.
One could be to multiply inherit from pure virtual classes and implement them in the derived class:
class Texture {};
class Color {};
class Square {};
class ITextured { public: virtual void setTexture(Texture) = 0; };
class IColored { public: virtual void setColor(Color) = 0; };
class ColoredSquare : public IColored, public ITextured, public Square {
Texture tex;
Color col;
public:
virtual void setTexture(Texture t) { tex = t; }
virtual void setColor(Color c) { col = c; }
};
This avoids having issues like Square inherit from Rectangle although a Rectangle method might alter only height, leaving the derived square class in violation of square-ness.
Composition is another approach, and there are many ways to implement similar ideas.
I'm new in C++ and I have maybe easy for you question.
class circle {
protected:
int r;
public:
circle(int re) { r=re; }
double surface() {
return 3.14*r*r;
}
};
class sphere : public circle {
public:
sphere(int r) : circle(r) {}
double surface(){
return 4*3.14*r*r;
}
};
And now, my problem is how I can do something like that: create a sphere object and using it to get surface not of a sphere but of a circle. Can I use somehow the same methods names in two classes, when one is inherited by the second one?
You can have access to the base class' surface method by appending circle:: before its name :
sphere sph(1);
double s = sph.circle::surface();
Your design is initially wrong. Public inheritance in C++ means that the child is-a specific kind of the parent. A sphere is not a circle!
Besides, if you do want to get the surface area of the sphere, you should make your surface function virtual:
class Circle {
public:
virtual double surface();
};
That way, when you override it in Sphere, the Sphere version will be called.
I have a virtual class Shape. class Rectangle, Triangle, Circle inherit from Shape and have different characteristics (size, number of side...).
I want to store different shape in a structure (let's say a vector).
so my vector would be: vector<Shape*> myvec;
I would like to know how it is possible to know if a given instance of a shape is present in the vector (ex: new Circle(diameter 10);).
I have heard about dynamic cast but I don't understand at all how to use it?
class Shape
{
public:
Shape(){}
virtual int Size()=0;
virtual int Sides()=0;
virtual bool isequal(const Shape & rhs)=0;
int size,sides;
};
class Circle : public Shape
{
public:
Circle(int diameter):size(diameter)
{
sides=0;
}
bool isequal(const Circle &rhs)
{
return size==rhs.size;
}
int size,sides;
};
class Rectangle: public Shape
{
Rectangle(int nbsides,int size1,int size2 ): sides(nbsides),size1(size1),size2(size2){}
bool isequal(const Rectangle &rhs)
{
return (size1==rhs.size1 && rhs.size2==size2);
}
int sides,size1,size2;
};
dynamic_cast is right:
Shape* shape = myvec[0];
Circle* circle = dynamic_cast<Circle*>(shape);
if(circle != nullptr)
; // it's a Circle! Do something circly.
else
; // it's not a Circle. Do something else.
But a better answer to the question is that, in a perfect world, you should use polymorphism such that it is rarely if ever necessary to do this.
Based on the additional comments below, I think you might want to use a pure virtual isequal() in Shape, with dynamic_casts inside the various implementations (the inside of a polymorphic comparison function is one of the few places I can use dynamic_cast without feeling the need to wash my hands afterwards :) ).
// edited out code that isn't directly relevant
class Shape
{
public:
virtual bool isequal(const Shape& rhs)=0;
};
class Circle : public Shape
{
public:
// snip
virtual bool isequal(const Shape &rhs) override
{
Circle* rhsAsCircle = dynamic_cast<Circle*>(&rhs);
if(rhsAsCircle == nullptr)
return false; // not a Circle; can't be equal
return size==rhsAsCircle->size;
}
};
Then elsewhere:
Circle searchCircle(10);
for(Shape* shape : myvec)
if(shape->isequal(searchCircle))
; // we have a match!
I'm not sure if I phrased my question as well as I liked to but I'll give an example to clear things up.
Here is the code:
class Shape;
class Circle;
class Triangle;
class Shape
{
Shape(void);
~Shape(void);
virtual void DrawShape(void) = 0;
}
class Circle : public Shape
{
/* .... constructor/destructor defined normally .... */
bool TestIntersection(Triangle* _triangle);
bool TestIntersection(Circle* _circle);
void DrawShape(void);
}
/* main.cpp */
...
Shape* shape;
Shape* circle = new Circle;
if(a == 0)
{
shape = new Circle;
}
else
{
shape = new Triangle;
}
circle->TestIntersection(shape);
I get the error that there is no acceptable conversion from Shape* to Circle* or Triangle*.
Why is this happening? Or do I need a way to determine which derived class has been set to the abstract class pointer?
What you need basically is this:
Visitor pattern
I noticed that you have not derived your supposedly derived classes from Shape. Fix that also. That is, Triangle and Circle should be derived from Shape. After that, read about Visitor pattern, its various implementations and usage. That will help you in solving your problem.
This is happening because you have actually not derived from the Shape.
class Circle: public Shape {
...
};
Your Circle class doesn't seem to inherit from Shape:
Try this:
class Circle : Shape
{
}