Sign in to follow this  

OO question

This topic is 4096 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am programming in c++. I need to have a renderable class, containing a position and orientation, and a pointer to a model. My problem is this: display->draw(renderable r) does not have access to the private aspects of renderable. Nor does it have access to the data of model. How do I give display->draw() access to renderable wihtout giving the rest of my program access to renderable?

Share this post


Link to post
Share on other sites
Making it a friend would work, but that doesn't look like a good solution to me, that's just locally breaking open encapsulation.

The classic OO way would be to have the renderable render itself: renderable->render(display). If however this render-operation depends on both the (dynamic) type of the display and that of the renderable object, you need multiple dispatch. The visitor design pattern offers a solution to this problem (also see double dispatch).

Share this post


Link to post
Share on other sites
Quote:
Original post by Simian Man
Make it a friend.

That is a poor suggestion. In most cases, friend is the option of last resort.

One solution is to modify your design, making a distinction between game objects and renderable objects. A game object renders itself by handing a renderable object to the renderer.

Share this post


Link to post
Share on other sites
Quote:
Original post by JohnBolton
Quote:
Original post by Simian Man
Make it a friend.

That is a poor suggestion. In most cases, friend is the option of last resort.

One solution is to modify your design, making a distinction between game objects and renderable objects. A game object renders itself by handing a renderable object to the renderer.


I did make a distinction between game objects and renderables, that's why they're called renderable rather than spacecraft element. The renderable needs to have a model(so you know what to draw), a position(so it knows where to draw it), and an orientation(so it know how to rotate it). All these things are updated using methods that renderable has.

To draw a spaceshippart, you call graphics->draw(renderable).

So I do pass the renderable to the draw function, as you said. Once draw has the renderable, how do I get the model out of it? and how do I then get the data out of the model?

Share this post


Link to post
Share on other sites
My idea of a Display should know how to draw dumb primitives (not necessarily a complete Model), not a generic Renderable.
A method of Renderable, say "render", taking a Display as a parameter should ask that Display to draw Models or other primitives.
This would allow encapsulation of Model instances that are created or modified on the fly, shared, switched, etc.
Moreover, Renderables that are composites, decorators etc. could delegate their rendering to other Renderables without twisty callbacks and undue visibility of their nature.

Share this post


Link to post
Share on other sites
Quote:
Original post by NIm
Quote:
Original post by JohnBolton
Quote:
Original post by Simian Man
Make it a friend.

That is a poor suggestion. In most cases, friend is the option of last resort.

One solution is to modify your design, making a distinction between game objects and renderable objects. A game object renders itself by handing a renderable object to the renderer.


I did make a distinction between game objects and renderables, that's why they're called renderable rather than spacecraft element. The renderable needs to have a model(so you know what to draw), a position(so it knows where to draw it), and an orientation(so it know how to rotate it). All these things are updated using methods that renderable has.

To draw a spaceshippart, you call graphics->draw(renderable).

So I do pass the renderable to the draw function, as you said. Once draw has the renderable, how do I get the model out of it? and how do I then get the data out of the model?


To recapitulate the 3 answers provided to you:

1. Make renderable a friend (Simian Man, but I consider this bad advice)
2. Provide accessor functions to all necessary data (Palidine)
3. Turn things around and have Renderable draw itself; it has access to its own data, and in general, OO means you put behavior where your data is (Palidine, LorenzoGatti and myself). I consider this to be the best option, since it gives you the most flexibility (code is always more general/flexible than data, so instead of having Renderable just raw data, have it be code). Also, if you have several kinds of display, and you need dynamic dispatch on the type of display, I again refer you towards the links about multiple dispatch above.

Share this post


Link to post
Share on other sites
Why is it such a bad idea to make draw() a friend?

Thank you for your other answers. I don't like providing accessors, as if I do this, then all other parts of the program can get to it too, and I don't want that. the data is part of the implementation, not the interface.

I like the idea of making renderable able to render itself, but this requires a redesign. Thank you for your help.

Share this post


Link to post
Share on other sites
Declaring a friend is almost the same as declaring things highly coupled. The point of having a Renderable interface is that you can hide behavior behind it, and have different things render themselves differently without anyone else knowing about it. If you just make Renderable a friend of Display, you suddenly make Display ultra-smart by putting all logic of rendering things in one class instead of spreading it around on a need-to-know basis.


It's possible that you don't need to redesign all that much if you're turning things around, having the Renderable render itself on the Display, just add an extra indirection:

void Display::render(Renderable* renderable)
{
renderable->render(this);
}

class Renderable
{
public:
virtual void render(Display* display) = 0;
};

class Mesh : public Renderable
{
public:
virtual void render(Display* display) { display->renderMesh(my_mesh); }

private:
Mesh* my_mesh;
};

class Composite : public Renderable
{
public:
Composite(Renderable* r1, Renderable* r2) : r1(r1), r2(r2) { }

virtual void render(Display* display)
{
r1->render(display);
r2->render(display);
}

private:
Renderable *r1, *r2;
};


Using this code, you can have Renderables which are actually composites or use some other logic than just rendering a mesh (see LorenzoGatti's post). You could see it as defining a whole new language for defining renderable stuff: composing, transforming, ... with each operation represented by a class.

Share this post


Link to post
Share on other sites
Thank you for your help. I really appreciate it. I think, for what I plan to do with my code, making display all-knowledgable is what I want. renderables don't know anything about displays and drawing, so I'd like to confine them to information about the appearanc of something, and confine display to knowledge of how to draw things. I really appreciate you clarifying that for me, and I thank you for your smaple code. It's really helpful, and I learn alot by it, but it's not right for this project. Thanks.

Share this post


Link to post
Share on other sites

This topic is 4096 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this