Hello everyone! I am trying to use polymorphism to have a little physics simulator that draws objects to the screen.

Each object has properties like mass, friction, position, velocity, acceleration and such similar things, as well as a pointer to a SHAPE object which describes the shape of the object.

The SHAPE class by itself has nothing in it, but I have several classes that inherit from shape.

I have a Circle class that stores the radius. I have a Rectangle class that stores the width and height. I'm also going to implement more classes, but i'm working with these for now.

A problem I'm encountering is drawing these classes. I understand that I could easily have the SHAPE class have a virtual method for drawing the shape, and simply call that method on the pointers later. However, I'm trying to keep my graphics and physics as separate as possible.
I do have functions for drawing circles and rectangles that work just fine when I give them the right information. For example,
drawCircle(double radius) would draw a a circle to the screen, and drawRectangle(double width, double height) would draw a rectangle. What I'm trying to accomplish is to have a drawShape(SHAPE* s) function that will call the appropriate draw function based on what type the shape really is.

Right now, I have drawShape(SHAPE* s), drawShape(Circle* c), and drawShape(Rectangle* r).
I was hoping to just call drawShape(pointer) and have the appropriate function be called automatically based on what the pointer really points to. But instead, the SHAPE function (default one that just draws a dot) is called all the time, since the pointer is of type SHAPE (even though it points to a Circle or Rectangle).

How would I make this polymorphism work for nonmenber functions without having a virtual draw() function in each shape?

Read up on dynamic_cast. It does what you're asking for (keeping in mind that adding new shapes won't be as simple as creating new polymorphic classes), though I'm sure some OOP nazi will wander in and give you an overly complicated design pattern that will also solve the problem. :icon_rolleyes:

dynamic_cast seems to do what I want it to, but it would only work if I already know what the pointer really points to. This is not the case. When I get a SHAPE*, I don't know if it's pointing to Circle, Rectangle, or SHAPE, and I need code that will determine which of these it is and call the appropriate function.

>but it would only work if I already know what the pointer really points to
Riiiight. Now you're starting to get from point A to point B. What did we do before the language dynamically made choices for us? We used switch statements! And if chains! Whooo!

Seriously, dynamic_cast evaluates to a null pointer if the type you requested isn't compatible. Meaning if you try to cast a SHAPE to a Circle, but it's really a Rectangle, you'll get a null pointer. So you try again with some "evil non-OOP" construct like this:

if ( Circle *p = dynamic_cast<Circle> ( pshape ) ) {
  // Dooby dooby doo with a circle
}
else if ( Rectangle *p = dynamic_cast<Rectangle> ( pshape ) ) {
  // Dooby dooby doo with a rectangle
}
else {
  // Fail gracefully
}

Hey, there is a difference in the number of arguments. So if you pass the required number of arguments, the corresponding function will be evaluated.

Hey, there is a difference in the number of arguments. So if you pass the required number of arguments, the corresponding function will be evaluated.

Overloading is not the same as polymorphism

>What i said is just polymorphism
No. What you said was overloading (function overloading to be exact). Read http://www.cs.bu.edu/teaching/cpp/polymorphism/intro/ point number 2.(What is polymorphism?).
In short, while discussing in the domain of C++, polymorphism is the term used to describe the dynamic polymorphism (virtual classes and function and related...) while overloading is the term used to describe static polymorphism.

If you classes all extend SHAPE then drawShape(SHAPE* s) will work because of liskov substitution

That's what I did before I posted here, and it didn't work. If you could just explain what you said in human english, maybe it is what I'm looking for.

And at the moment, I'm using typeid(*ptr) to determine what type it is.

That's what I did before I posted here, and it didn't work. If you could just explain what you said in human english, maybe it is what I'm looking for.

And at the moment, I'm using typeid(*ptr) to determine what type it is.

http://en.wikipedia.org/wiki/Liskov_substitution_principle If you have the following class structure:

Shape
         /     \
   Square       Circle

Then you see that Circle and Square are both Shapes so if you have Shape::drawShape(Shape* s) then it will work on both Square and Circle since, as I said before, they are shapes.

However, this brings me to the point about why you wouldn't have a method drawShape(Shape* s) in your Shape or any descendant Shape classes. You'd have a Shape::draw() that acts on this . In OOP you should write your methods as if they are actions that object can perform on itself.

You could extrapolate this point further to preserve separation of concern by having Shape::draw() be a wrapper for a ShapeDrawer::draw(Shape* s) where you have a secondary class who's only job is to draw whatever shape it's given. But this is an different problem entirely.

As a matter of fact, I do have something that qualifies as a shape drawer class. What I have is a shape_manager class which keeps track of all the shapes that I will be performing operations on, and a shape_manager_drawer class which stores a pointer to a shape_manager, and has a draw() function which calls drawShape(ptr) on each of the shapes in the shape_manager class pointed to by it's internal pointer.

My reason for not giving the shapes a draw function is because the shapes are used for physics simulation purposes only. I'm trying to keep my graphics and physics as separate as possible. At this stage, I'd like to see exactly what the underlying shapes are to make it easier to debug, but later on I'm going to have objects that look nothing like their underlying shapes. I might have a simple car that's represented by a single rectangle. In that case, I'd want the shape_manager_drawer.draw() to produce the car texture I selected rather than the rectangle, while for the next object that I'm still debugging (which might be a rectangle, or a circle, or a triangle that I'll implement soon) I might still want it to draw the underlying shape.

What I'm trying to say is that

draw()

is not an action which shape can take, nor is it an action that shape should be able to take. Therefore, I am following the principles of OOP by not having the draw function be a member of the shape class.

At the moment, I'm using typeid(*shape_ptr)==typeid(circle) or typeid(*shape_ptr)==typeid(rectangle) to get the job done.

If you're abstracting it like that then drawer class shouldn't even need to know what a shape is. It just receives and acts on data. So you wouldn't want to actually pass a shape to that function, you'd probably want to pass coordinates to draw or something along those lines. It's not the Drawer class's job to figure out what to draw, it just draws.

If you're abstracting it like that then drawer class shouldn't even need to know what a shape is. It just receives and acts on data. So you wouldn't want to actually pass a shape to that function, you'd probably want to pass coordinates to draw or something along those lines. It's not the Drawer class's job to figure out what to draw, it just draws.

You're wrong. What you're describing is a graphics class. I have that, it's a simple layer I wrote on top of OpenGL. That class just takes in data (vertexes) and outputs it to the screen. What I want form my drawer class is to decypher the data from my shape class and pass it to my graphics class.

You're wrong. What you're describing is a graphics class. I have that, it's a simple layer I wrote on top of OpenGL. That class just takes in data (vertexes) and outputs it to the screen. What I want form my drawer class is to decypher the data from my shape class and pass it to my graphics class.

It's just down to semantics now since what you're describing can't really be called a 'Drawer' class since it's not 'Drawing', it's more of a GraphicsDriver. Name it what you wish but you have the right idea.

It's just down to semantics now since what you're describing can't really be called a 'Drawer' class since it's not 'Drawing', it's more of a GraphicsDriver. Name it what you wish but you have the right idea.

Thanks for the useful solution to my problem!

Since starting this post, I have changed the way my shapes are represented. Instead of having a separate class for each shape, I have one unified class that stores the vertexes of a given shape as offset vectors in an array. This way, I can have one class represent any arbitrary shape.
So now, I only need one function to draw a shape, since all the information necessary to draw it is stored inside the class.

Nevertheless, I think it's interesting to argue about a way to achieve dynamic polymorphism outside of classes.

PS: I can't quite figure out how to decode your signature. Do the pluses represent increments? Are the <> signs for shifts or character separators? Are they characters themselves?

Thanks for the useful solution to my problem!

Since starting this post, I have changed the way my shapes are represented. Instead of having a separate class for each shape, I have one unified class that stores the vertexes of a given shape as offset vectors in an array. This way, I can have one class represent any arbitrary shape.
So now, I only need one function to draw a shape, since all the information necessary to draw it is stored inside the class.

Nevertheless, I think it's interesting to argue about a way to achieve dynamic polymorphism outside of classes.

PS: I can't quite figure out how to decode your signature. Do the pluses represent increments? Are the <> signs for shifts or character separators? Are they characters themselves?

haha, so you've gone from trying to correctly implement polymorphism to ignoring it entirely? *shrug* I guess that's your choice.

My signature is geekcode

haha, so you've gone from trying to correctly implement polymorphism to ignoring it entirely? *shrug* I guess that's your choice.

My signature is geekcode

ha, well I realized that polymorphism wasn't the best choice for representing shapes. I still use it for constraints (all constraints share the same public interface, with additional members where necessary).

Splitting everything into triangles seemed to solve lots of problems for me.

BTW:

h! r--- !y+

This article has been dead for over six months. Start a new discussion instead.