Polymorphism with Linked Lists

Started by
20 comments, last by tmarques4 12 years, 5 months ago

If you can put enough methods in Object to make it a useful interface, polymorphism might work for you. Geometric figures might have a method to draw themselves in a window, they might be able to return a bounding box... Perhaps then you can have a linked list of your objects, but it needs to be the case that most of the code can handle objects just using the Object interface. The sample of code you posted where you tried to set hum->quad is an example of code that needs to know more than the Object interface.

I use polymorphism in very few places. I do it when I can have a factory function that returns a pointer to the base class and no other part of the code needs to know what exact type was returned. If I ever find the need to use dynamic_cast (which is what would allow you to get a more specific pointer from a pointer to Object), I reconsider my design, because the abstraction is not working.


All geometric shapes must be derived from a base class "Object", which will have only virtual functions that operates on the geometric shapes, just as you mentioned: Draw(), Rotate(), Translate() etc... This Object will describe a "protocol" that all those derived geometric shapes must follow. Is it a proper data structure for considering polymorphism? Or is it recommended to create separate linked list for those, I'm trying to avoid this since I was looking at a single volatile structure, in which I just have to add geometry without the need to be concerned about what they actually represent.
Tiago.MWeb Developer - Aspiring CG Programmer
Advertisement

The question isn't about what form the data takes. The question is, what do you do with the data? That really changes the best approach.

I guess what I'm getting at is, why do you want all of these different objects in a single linked list? What will that gain you that alternatives will not? What sort of processing are you doing on the list?


Convenience I guess.

It's "easier" to handle a single data structure than having to handle multiple ones if you have a good implemented polymorphic structure. Polymorphism is not a must to implement the code but would be a nice approach.
Tiago.MWeb Developer - Aspiring CG Programmer
If it really were easier and more convenient, you wouldn't need this thread to help you figure it out. In the modern world of data-oriented architectures, where cache coherence and rapid batching of data are far more important than whatever meager convenience benefits polymorphism offers, I would think that this approach might be a step backward. Any time you have to hop out of a contiguous chunk of memory and follow a pointer off to somewhere else, you risk stepping out of cache unnecessarily. As clunky as interleaved, fixed-format vertices might be to work with, at least they offer the benefit of being very cacheable without virtualized interfaces or pointer indirections to access the individual components.

Convenience I guess.

It's "easier" to handle a single data structure than having to handle multiple ones if you have a good implemented polymorphic structure. Polymorphism is not a must to implement the code but would be a nice approach.




I'm honestly a little confused here. You sound comfortable enough with the idea of polymorphism to identify it as a useful solution for your current situation, but you're missing some of the most basic concepts behind how it works, as evidenced by the Object*-vs-Quad* confusion earlier.

I'm not sure exactly how to help at this point...?

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

I think before being able to help you we need to know what exactly you want to do with this code. Is it for a render engine? A 3D modelling tool? Do you use Direct3D, OpenGL or even software rendering?
Generally I try to avoid polymorphism whenever possible. (Composition over inheritance) With such small structures virtual methods are better avoided as stated before. It is better to operate on a whole bunch of them at once.

When I started learning OOP I was, like many, under the impression that everything has to be a class and that inheritance was the best way to extend classes.
Doing relational database design and normalizing DB models has really helped me think more in terms of data and algorithms vs. single object manipulation.
@ApochPiQ

I'm not sure exactly how to help at this point...?[/quote]

Well, I have worked out a solution based on alvaro's reply that does what I wanted in the first place. That helped me a lot to understand polymorphism and I think I have a clearer idea now as I did one week ago. If someone could give me a tip or two as to how right or wrong this implementation is I'd appreciate it.


#include <stdio.h>

class generic
{
public:
virtual void imprime(){printf("this is generic...\n");}
};

class point : public generic
{
public:
char *nome;
point(){nome = "point";}
void imprime(){printf("this is %s...\n", nome);}
};

class line : public generic
{
public:
char *nome;
line(){nome = "line";}
void imprime(){printf("this is %s...\n", nome);}
};

class triangle : public generic
{
public:
char *nome;
triangle(){nome = "triangle";}
void imprime(){printf("this is %s...\n", nome);}
};

class quad : public generic
{
public:
char *nome;
quad(){nome = "quad";}
void imprime(){printf("this is %s...\n", nome);}
};

int main()
{
void *hum[5];
hum[0] = new generic();
hum[1] = new point();
hum[2] = new line();
hum[3] = new triangle();
hum[4] = new quad();

((generic *)hum[0])->imprime();
((generic *)hum[1])->imprime();
((generic *)hum[2])->imprime();
((generic *)hum[3])->imprime();
((generic *)hum[4])->imprime();
}


Here I just create and set a bunch of void pointers to different data types and can test what objects they represent by the printf function, each one of the "imprime" at main have a different output on the terminal and, even though they are different types, the program doesn't need to know about this.

Now, think of those "imprime" functions as being a "render" function. This render function is part of generic class and is virtual, each geometry that derives from this generic class will have this "render" function behaving differently according to each geometry's "private variables", like render needing to set normals for tris and quads and not for points and lines, etc...

This way I can have a linked list of different geometries like I stated before and, when I need to render them all I just need to pass through each node and cast render() recursively:


void Render(void *linkedList)
{
((generic *)linkedList)->render();
Render((((generic *)linkedList)->next()));
}


Also, one other reason for me to want to have a single linked list with different data types is that I want a history of recently created objects, not mattering their types, and I want to switch between objects on the fly, forward or backward. Linked list is a good alternative. I think if I can design such a structure there are lots of benefits.
Tiago.MWeb Developer - Aspiring CG Programmer

I think before being able to help you we need to know what exactly you want to do with this code. Is it for a render engine? A 3D modelling tool? Do you use Direct3D, OpenGL or even software rendering?
Generally I try to avoid polymorphism whenever possible. (Composition over inheritance) With such small structures virtual methods are better avoided as stated before. It is better to operate on a whole bunch of them at once.

When I started learning OOP I was, like many, under the impression that everything has to be a class and that inheritance was the best way to extend classes.
Doing relational database design and normalizing DB models has really helped me think more in terms of data and algorithms vs. single object manipulation.


I haven't thought about graphics engines yet, I'm just implementing a data structure for 3d models. It should not depend on the engine used, being rather a generic structure.

Polymorphism works when you have many classes that share the same methods, as stated by alvaro, and is exactly what happens in my case, not?

Classes help organizing code and having a clearer view of what the program does and how it's going to do it. I don't think inheritance is the best way to extend classes though, every problem has a unique solution.

I must admit I don't handle relational databases, aside from SGBD's. I appreciate and will take your advice.
Tiago.MWeb Developer - Aspiring CG Programmer
There is no need for using a void* here. Just use a generic* directly and skip all the icky casting ;-)

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

Everything sorted them.
Thanks everyone very much for the help!
Tiago.MWeb Developer - Aspiring CG Programmer
For other future readers of this thread:

Usually your primitives for the geometry are of the same type, all triangles, all lines, etc.. You don't want to make the primitive to be a polymorphic, but rather the collection of them. The solution is seen in post #2, but renaming the derived classes as PointGeometry and LineGeometry would make the case more clear, as is seen from the misunderstanding in post #3.

If you really want a single geometry to have different types of primitives, just add a collection for each type.

This topic is closed to new replies.

Advertisement