Inheritance, containers with base type, typecasting

Started by
3 comments, last by the_edd 12 years, 3 months ago
hello,
I have a class Node, and another one called TransformationNode : public Node

in a function called updateTransform, I iterate trough a vector in the base class vector<Node*> nodes.

In the base class there are no such functions, lets say void addVec(); and TransformationNode* updateTransfrom();

and updateTransfrom() is something like this...


TransformationNode* updateTransfrom() {
auto beg = nodes.begin();
auto end = nodes.end();

while(beg != end) {
TransformationNode* tmp = static_cast<TransformationNode*>(*beg);
tmp->addVec();
beg++;
}
return tmp;
}



I don't want to do type cast alot, is this the only way of doing this ? How do I tell my compiler that, "nodes" vector is already containing TransformationNode* ?

And I have an other very similar issue,
I have a functon called Graph* getGraph() in base, and a member Graph* mGraph
However, implementation in TransformationNode class must be somethig like this SceneGraph* getGraph(); and the member mGraph's type also must be TransformationNode*
I get around this issue by type casting the pointer returned by getGraph() to a TransformationNode* pointer

I wanted to know if my design is problematic or there is a better solution to these kind of problems.
And if you know any, good books or articles about this kind of usage of the c++ and object oriented design

thank you for taking your time.
www.lostchamber.com
Advertisement

#ifndef AMZ_SCENE_NODE_H
#define AMZ_SCENE_NODE_H
#include "amzPrerequisite.h"
#include "amzEntity.h"
#include "amzNode.h"
//TODO: instead of lists and vectors, use map because there are a lot of query on the node lists etc..!
namespace amz {
typedef unsigned long NodeId;
typedef AmzVector<Entity*> EntityArray;
typedef AmzVector<SceneNode*> NodeArray;
class _AmzExport SceneNode : public Node {
public:
enum TransformSpace {
TS_WORLD,
TS_LOCAL,
TS_PARENT
};
/// Remove all of its entity and nodes
/// Doesn't delete the child nodes, they may be added to the scene again
/// else they must be deleted
virtual ~SceneNode();
/// Attach an entity to node, if entity doesn't have a parent already
virtual void addEntity(Entity* entity);
/// Attach an unparented node to this node
virtual void addNode(SceneNode* node);
/// Remove an entity from the entity list of the node and return a pointer to the removed entity
/// If entity is not in the list, function returns a null pointer
/// Deleting the memory allocated by entity is responsibility of the user
virtual Entity* removeEntity(String name);
/// Remove an entity from the entity list of the node and return a pointer to the removed entity
/// If entity is not in the list, function returns a null pointer
/// Deleting the memory allocated by entity is responsibility of the user
virtual Entity* removeEntity(EntityId id);
/// Remove a node from the childNode list of the node and return a pointer to the removed node
/// If node is not in the list, function returns a null pointer
/// Deleting the memory allocated by node is responsibility of the user
virtual SceneNode* removeNode(String name);
/// Remove a node from the childNode list of the node and return a pointer to the removed node
/// If node is not in the list, function returns a null pointer
/// Deleting the memory allocated by node is responsibility of the user
virtual SceneNode* removeNode(NodeId id);
/// Creates an unnamed child node
virtual SceneNode* createChild(Vector3 translate = Vector3(0, 0, 0), Quaternion rotate = Quaternion());
/// Creates a child node with given name
virtual SceneNode* createChild(String name, Vector3 translate = Vector3(0, 0, 0), Quaternion rotate = Quaternion());
/// Translates node by t
void translate(Vector3 t);
/// Rotates node by angle around axis
void rotate(Real angle, Vector3 axis);
/// Rotates node by q
void rotate(Quaternion& q);
/// Rotates node by angle around x axis
void rotate_x(Real angle);
/// Rotates node by angle around y axis
void rotate_y(Real angle);
/// Rotates node by angle around z axis
void rotate_z(Real angle);
/// Scales given node by s
void scale(Vector3 s);
/// Decides whether the node inherits its parent orientation or not
void setInheritOrientation(bool inherit);
/// Sets translation of the node
void setTranslation(Vector3& translation);
/// Sets orientation of the node
void setOrientation(Quaternion& orientation);
/// Sets scale of the node
void setScale(Vector3& scale);
/// Sets parents accumulated translation
void _setInheritedTranslation(Vector3 translation);
/// Sets parents accumulated orientation, if inherit orientation is true
void _setInheritedOrientation(Quaternion orientation);
/// Sets parents accumulated scale
void _setInheritedScale(Vector3 scale);
/// Sets the parent node of this node
virtual void _setParent(SceneNode* parent);
/// Unparent the node
virtual void _unParent();
/// Updates the node, scene manager does this
virtual void _update();
/// Returns translation of the node
Vector3 getTranslation(TransformSpace relativeTo = TS_PARENT);
/// Returns orientation of the node
Quaternion getOrientation(TransformSpace relativeTo = TS_PARENT);
/// Returns scale of the node
Vector3 getScale(TransformSpace relativeTo = TS_PARENT);
/// Returns accumulated translation of node's parents
Vector3 getInheritedTranslation();
/// Returns accumulated orientation of node's parents
Quaternion getInheritedOrientation();
/// Returns accumulated scale of node's parents
Vector3 getInheritedScale();
/// Return transformation matrix in requested transformation space
virtual Matrix4 getTransformationMatrix(TransformSpace relativeTo = TS_PARENT);
/// Returns name of the node
String getName();
/// Returns a child entity in entity list
virtual Entity* getEntity(String name);
/// Returns a child node in node list
virtual SceneNode* getNode(String name);
/// Returns entity list iterator
EntityArray::iterator getEntityIterator(bool end = false);
/// Returns node list iterator
dNodeArray::iterator getNodeIterator(bool end = false);
/// Returns node id
NodeId getId();
/// Returns parent node
virtual SceneNode* getParent();
/// If node is in camera frustum it is visible
bool isVisible();
/// If node is in active region it is active
bool isActive();
/// Returns true if setInheritOrientation is true
bool isInheritOrientation();
/// Returns true if node requires update
bool isDirty();
protected:
EntityArray mEntityArray;
Vector3 mTranslation;
/// Accumulated translation data of parent
Vector3 mInheritedTranslation;
/// Translation data which is used to update node when node is dirty
Vector3 mUpdateTranslation;
Quaternion mOrientation;
/// Accumulated orientation data of parent
Quaternion mInheritedOrientation;
/// Orientation data which is used to update node when node is dirty
Quaternion mUpdateOrientation;
Vector3 mScale;
/// Accumulated scale data of parent
Vector3 mInheritedScale;
/// Scale data which is used to update node when node is dirty
Vector3 mUpdateScale;
NodeId mId;
bool mIsInheritOrientation;
/// Dirty flag indicates that, this node must get update during update of the node
bool mDirty;
SceneManager* mSceneManager;
private:
friend class SceneManager;
SceneNode(SceneManager* manager);
SceneNode(SceneManager* manager, Vector3 translate, Quaternion rotate);
SceneNode(SceneManager* manager, String name, Vector3 translate = Vector3(0,0,0), Quaternion rotate = Quaternion());
/// If node is in camera frustum this flag is true
bool mVisible;
/// If node is in active region this flag is true
bool mActive;
/// Returns next available id.
NodeId getNextId();
/// This variable provides a starting ID value for all resources.
static NodeId _id;
};
}
#endif
www.lostchamber.com

#ifndef AMZ_NODE_H
#define AMZ_NODE_H
#include "amzPrerequisite.h"
namespace amz {

typedef unsigned long dNodeId;
typedef AmzVector<Node*> dNodeArray;
class _AmzExport Node {
public:
Node();
Node(String name);
/// Destruct a node with all of its child nodes and deallocate used memory
~Node();
/// Attach an orphan node to this node
virtual void addNode(Node* node);
/// Remove a node from the childNode list of the node and return a pointer to the removed node
/// If node is not in the list, function returns a null pointer
/// Deleting the memory allocated by node is responsibility of the user
virtual Node* removeNode(String name);
/// Remove a node from the childNode list of the node and return a pointer to the removed node
/// If node is not in the list, function returns a null pointer
/// Deleting the memory allocated by node is responsibility of the user
virtual Node* removeNode(dNodeId id);
/// Creates an unnamed child node
virtual Node* createChild();
/// Creates a child node with given name
virtual Node* createChild(String Name);
/// Sets the parent node of this node
virtual void _setParent(Node* parent);
/// Sets parent to null
virtual void _unParent();
/// Remove this node from its parent's list, sets mParent to null
virtual void orphan();
/// Returns name of the node
String getName();
/// Returns a child node in node list
virtual Node* getNode(String name);
/// Returns a child node in the node list
virtual Node* getNode(dNodeId id);
/// Returns node list iterator
dNodeArray::iterator getNodeIterator(bool end = false);
/// Returns node id
dNodeId getId();
/// Returns parent node
virtual Node* getParent();
protected:
String mName;
Graph* mGraph;
dNodeArray mNodeArray;
Node* mParent;
dNodeId mId;
Node(Graph* graph);
Node(Graph* graph, String name);
/// Returns next available id.
dNodeId getNextId();
private:
friend class Graph;
/// This variable provides a starting ID value for all resources.
static dNodeId _id;
};

class CriteriaSet {
public:
enum SortCriteria {
BY_PRIORITY,
BY_RENDERER,
BY_TOPOLOGY
};
CriteriaSet();

void addCriteria(SortCriteria criteria);
void removeCriteria(SortCriteria criteria);
void removeCriteria(int index);
void getCriteria(int index);
private:
AmzVector<SortCriteria> mCriteriaArray;
};
class RenderBatch {
public:
void getMaterial();
void getRenderer();
void getMesh();

};
AmzVector<RenderBatch*> RenderBatchArray();
class _AmzExport Graph {
public:
/// Returns root node
Node* getRootNode();
/// Job is decomposed and placed in to graph acording to criteria set
void addRenderJob();
/// Add render job list
void addRenderJobList();

/// Each depth of the graph is sorted according to criteria set
/// If not set one, default is, priority -> renderer -> topology
void setCriteriaSet();

static Node* dCreateNode() { return new Node(NULL); }
};
}
#endif
www.lostchamber.com
Generally, if you find yourself needing to cast more than you would like you should consider rethinking your design. In the example in the original post, to get rid of the cast you basically have three choices

1.) Some radical re-design such that the updateTransform function no longer exists in its current form. It would require knowledge of your application and codebase to be more specific.

2.) Make updateTransform deal with a vector of TransformNodes rather than a vector of Nodes. I mean, it is casting every single item in a vector to a different type, so why not just give it that type to begin with? You had to have created a vector of nodes that only contains TransformNodes somewhere, right?

3.) Make Node have an "addVec" virtual member function that is a noop or throws an exception when called on the base class. (or is pure virtual if the base class is abstract)
... or use the visitor pattern (yucky, IMHO, but common in scenegraph APIs), or give every node a transform.

This topic is closed to new replies.

Advertisement