Sign in to follow this  
Basiror

Avoiding Capability Queries

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;
}
p->attach(s){s->is_attachable_to(*this);}

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

e.g.:
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

e.g.:
root->octreeroot:
check if object is of type 'cullable', insert on success
root->physicworldroot:
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

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