Jump to content
  • Advertisement
Sign in to follow this  

Avoiding Capability Queries

This topic is 4120 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

Hi, I am currently searching for a proper solution to get rid of capability queries in a class hierarchy with multiple inheritance Example: You have a basic graph implementation inside class node; Now at runtime you would like to attach objects to the octree, but it makes no sense to attach objects that are not cullable, so since I am using multiple inheritance I had to make use of cross-casting dynamic_cast<cullable*>(p) == 0. This however makes the whole class hierarchy pretty unflexible regarding future extensions. So the solution I came up with is, instead to do the cross-casts in the octree class or any other potential owner of a subobject, I move this query to a virtual function Old solution: The cross-casts are done within the attach function of the parent, which pollutes the whole hierarchy.
class octree_node : public node : public cullable
//! returns true if attaching was successful
virtual bool attach(node& n);

octree_node *p = new ...;

node & s = some object reference

if(!p->attach(s)) error;

My proposal: Do the cross-casts in the object you want to attach, this however moves the responsibility to the programmer implementing the objects.
class node
//! returns true if attachable, n is the not it shall be attached to
virtual bool is_attachable_to(node& n) const;

Do you know a better solution for that problem? Maybe some sort of capability lists?? octree_node.capalist ={ "cullable" }; if( capalist.find(object.capability())) ... thx for your comments in advance

Share this post

Link to post
Share on other sites
I'm not sure I understand what your problem is and why you need RTTI at all.
But you could write a specific subclass of node for cullable stuff that is itself cullable.
Like this:

class CullableNode: public node, public Cullable {
Cullable* myCullable;
public void doCullingSpecificStuff() { myCullable->doCullingSpecificStuff(); }

void octree_node::attachCullable(Cullable* c) {
attach(new CullableNode(c))

Share this post

Link to post
Share on other sites
Well, the point is how and where do you call attachCullable(...)

I am currently working on a scene graph implementation.
As you might know, there are proposals to use several independent scene graphs to represent seperate logical relationships

My aim is to implement a generalized graph, that updates itself upon invalidation of a leaf / child. Instead of inserting all nodes into seperate graphs, I want to use the root not as sort of distributor. In the context of programming that means, I don t have to take care about inserting notes into the proper graph, I just tell the scenegraph: "here s a new object, handle it properly"

Inserting a node works like this.
root->attach( some object derived from node + interfaces);

the 'root' node is linked to the root nodes of the sub graphs

root->{octreeroot; lightfrustumhierarchyroot; physicworldroot;...}

The root node passes the objects down the hierarchy, where I want to decide whether the object can be attached to a node or not

check if object is of type 'cullable', insert on success
check if object is of type physicnode, insert on success

Now to implement different different space partition types I could derive octree_node from a spacepartition node

class spacepartition_node : public node, public cullable;
class octree_node : public spacepartition_node;
class quadtree_node : public spacepartition_node;

And each object that shall be inserted into such a partitiontree has to tell whether is implements the necessary interface required by spacepartition_node;

With my previous proposal:

bool object::is_attachable_to( node& n)
return (dynamic_cast<spacepartition_node*>(&n) != 0)

Using your approach requires me to insert the nodes into each subgraph seperately, this on the one hand eleminates the need of RTTI completely, on the other hand it seperates the graphs, which is what I wanted to avoid in the first place.

Once an object is invalidated it notifies its parents, the parents try to reattach the object, on failure they either propagate it to their parents, or try to reinsert it into the subgraph through the subgraph's root node, this behaviour can be controlled via a flag set in the base class node at initialization.
This way I can keep the amount of graph traversion at a minimum even for large scenes.
I also don t have to keep track about invalidated objects, since that job was moved to the scene graph in the first place.

I am really undecided about the way to go. On the one hand the RTTI causes some overhead, on the other hand some additional work on the CPU won't hurt that much, since the 3d engine where I want to integrate it into will be fillrate limited anyways.

[Edited by - Basiror on June 8, 2007 7:08:21 AM]

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!