I have a type heirarchy:
class Object {
...
};
class Node : public Object {
...
};
class Leaf : public Object {
...
};
class Something : public Node {
...
};
class SomethingElse : public Leaf {
...
};
In other words, absolutely every class inherits Object either directly or indirectly.
The constructor for every object is in the following format:
ClassType(Object * parent)
However, by design only a Node can be a parent, while a Leaf is a terminating node;
In the moment, in every constructor I am doing the following:
Node * p = dynamic_cast<Node *>(parent);
if (p) p->adopt(this);
else qDebug() << "for some reason cast failed";
So, my primary question is this - considering that every parent object can only be a Node or derived from Node, is it safe to use static_cast instead? Naturally, the primary concern is performance, right now I get about 4 million nodes created per second, which does not seem like a bottleneck, but still, this is barebone hierarchy, as it is populated with more logic it will get slower, so if I can get rid of the dynamic_cast it will be a good thing.
I have verified that for Something s it will be true that &s == static_cast<Node *>(&s) == dynamic_cast<Node *>(&s) but I am not sure whether I can "put all my eggs into that basket" so to speak - is it guaranteed that I can "blindly" reuse the address of every directly or indirectly derived from Node class as a Node * as long, regardless of whether it is created on the stack, Object * s = new Something, Node * s = new Something, Something * s = new Something or any of the many possible variations?
My secondary question is whether this design is a good idea. I do realize that it is somewhat pointless to pass an Object * for parent, considering that only Nodes can be parents, but the Node itself stores its children internally as Object * because not all children derive from Node. Naturally, any recommendations to make this more elegant are welcomed.
If You are worying about this cast, maybe you should define parent member as Node? Then You will never need to cast. Also you will be sure you always use Node as a parent.
Now, for some logical reasons you know that a parent will always be a Node, hence you should use static_cast.
Problem is, it's really hard to debug this code if your assumption fails. What you might want to do is something like this:
#ifdef NDEBUG
Node * p = static_cast<Node*>(parent);
#else
Node * p = dynamic_cast<Node *>(parent);
assert(p);
#endif
p->adopt(this);
This can be easily achieved with boost::polymorphic_downcast.
Node * p = boost::polymorphic_downcast<Node*>(parent);
My professor of languages at university told us to avoid as much as possible dynamic cast and it is something that I try to do every time I have to develop a complex hierarchy.
That being said, if you know exactly that Parent points to a Node then a static cast is safe.
A pointer to member of some class D can be upcast to a pointer to
member of its base class B. This static_cast makes no checks to ensure
the member actually exists in the runtime type of the pointed-to
object.
In short, if you know that D will always be derived from B, using static_cast is safe.
If performance is one of your concerns, I would suggest simplifying (flatten) your hierarchy.
If you know that parent is a Node, then the static_cast does the right thing.
But if you know that parent is a Node, then why not change the constructors (and probably whatever parent pointer you keep inside Object) to reflect this reality?
You can create a fast (O(1), one virtual call) version for your cast if you create a virtual function which transforms object to node if it is a node. In case of succes you get a node* and in case of a failure you get nullptr. This cast is hidden inside the mechanism of the virtual call and thus type safe.
class node;
class object {
// other things
public:
node const* as_node() const { return 0; }
node* as_node() { return 0; }
};
class node {
// other things
public:
node const* as_node() const { return this; }
node* as_node() { return this; }
};
When you do downcast (from Object to Node), you have to use dynamic_cast. For the other way around (Node to Object), static_cast is fine.
The fact that you have to downcast using dynamic_cast indicates a problem in design.
I do not know details, but you could change constructors. Instead of taking Object* parent, you can take Node* parent and Leaf* parent.
So, change :
struct A
{
A( Object* parent );
};
to :
struct A
{
A( Node* parent );
A( Leaf* parent );
};
also, instead of pointers, I would use references.
Another option is to implement the adopt method in all classes. In classes that do not need it, will use default no-op operation, and override it in classes that actually do something. Then you do not need to cast.
class Object {
virtual void foo(){ /*no-op*/ }
};
class Node : public Object {
virtual void foo(){ /* hi-ho */ }
};
class Leaf : public Object {
// uses default foo
};
void callFoo( Object & obj )
{
// no need to cast
obj.foo();
}
Related
I am currently trying to learn how to use smart pointers. However while doing some experiments I discovered the following situation for which I could not find a satifying solution:
Imagine you have an object of class A being parent of an object of class B (the child), but both should know each other:
class A;
class B;
class A
{
public:
void addChild(std::shared_ptr<B> child)
{
children->push_back(child);
// How to do pass the pointer correctly?
// child->setParent(this); // wrong
// ^^^^
}
private:
std::list<std::shared_ptr<B>> children;
};
class B
{
public:
setParent(std::shared_ptr<A> parent)
{
this->parent = parent;
};
private:
std::shared_ptr<A> parent;
};
The question is how can an object of class A pass a std::shared_ptr of itself (this) to its child?
There are solutions for Boost shared pointers (Getting a boost::shared_ptr for this), but how to handle this using the std:: smart pointers?
There is std::enable_shared_from_this just for this purpose. You inherit from it and you can call .shared_from_this() from inside the class. Also, you are creating circular dependencies here that can lead to resource leaks. That can be resolved with the use of std::weak_ptr. So your code might look like this (assuming children rely on existence of parent and not the other way around):
class A;
class B;
class A
: public std::enable_shared_from_this<A>
{
public:
void addChild(std::shared_ptr<B> child)
{
children.push_back(child);
// like this
child->setParent(shared_from_this()); // ok
// ^^^^^^^^^^^^^^^^^^
}
private:
// note weak_ptr
std::list<std::weak_ptr<B>> children;
// ^^^^^^^^
};
class B
{
public:
void setParent(std::shared_ptr<A> parent)
{
this->parent = parent;
}
private:
std::shared_ptr<A> parent;
};
Note however, that calling .shared_from_this() requires that this is owned by std::shared_ptr at the point of call. This means that you cannot create such object on stack anymore, and generally cannot call .shared_from_this() from within a constructor or destructor.
You have several problems in you design, that seem to stem from you misunderstanding of smart pointers.
Smart pointers are used to declare ownership. You are breaking this by declaring that both the parents owns all children, but also that each child own it's parent. Both can't be true.
Also, you are returning a weak pointer in getChild(). By doing so, you are declaring that the caller shouldn't care about the ownership. Now this can be very limiting, but also by doing so, you must make sure that the child in question won't get destroyed while any weak pointers are still held, if you would use a smart pointer, it would get sorted out by itself.
And the final thing. Usually, when you are accepting new entities, you should usually accept raw pointers. Smart pointer can have their own meaning for swapping children between parents, but for general usage, you should accept raw pointers.
I am currently trying to learn how to use smart pointers. However while doing some experiments I discovered the following situation for which I could not find a satifying solution:
Imagine you have an object of class A being parent of an object of class B (the child), but both should know each other:
class A;
class B;
class A
{
public:
void addChild(std::shared_ptr<B> child)
{
children->push_back(child);
// How to do pass the pointer correctly?
// child->setParent(this); // wrong
// ^^^^
}
private:
std::list<std::shared_ptr<B>> children;
};
class B
{
public:
setParent(std::shared_ptr<A> parent)
{
this->parent = parent;
};
private:
std::shared_ptr<A> parent;
};
The question is how can an object of class A pass a std::shared_ptr of itself (this) to its child?
There are solutions for Boost shared pointers (Getting a boost::shared_ptr for this), but how to handle this using the std:: smart pointers?
There is std::enable_shared_from_this just for this purpose. You inherit from it and you can call .shared_from_this() from inside the class. Also, you are creating circular dependencies here that can lead to resource leaks. That can be resolved with the use of std::weak_ptr. So your code might look like this (assuming children rely on existence of parent and not the other way around):
class A;
class B;
class A
: public std::enable_shared_from_this<A>
{
public:
void addChild(std::shared_ptr<B> child)
{
children.push_back(child);
// like this
child->setParent(shared_from_this()); // ok
// ^^^^^^^^^^^^^^^^^^
}
private:
// note weak_ptr
std::list<std::weak_ptr<B>> children;
// ^^^^^^^^
};
class B
{
public:
void setParent(std::shared_ptr<A> parent)
{
this->parent = parent;
}
private:
std::shared_ptr<A> parent;
};
Note however, that calling .shared_from_this() requires that this is owned by std::shared_ptr at the point of call. This means that you cannot create such object on stack anymore, and generally cannot call .shared_from_this() from within a constructor or destructor.
You have several problems in you design, that seem to stem from you misunderstanding of smart pointers.
Smart pointers are used to declare ownership. You are breaking this by declaring that both the parents owns all children, but also that each child own it's parent. Both can't be true.
Also, you are returning a weak pointer in getChild(). By doing so, you are declaring that the caller shouldn't care about the ownership. Now this can be very limiting, but also by doing so, you must make sure that the child in question won't get destroyed while any weak pointers are still held, if you would use a smart pointer, it would get sorted out by itself.
And the final thing. Usually, when you are accepting new entities, you should usually accept raw pointers. Smart pointer can have their own meaning for swapping children between parents, but for general usage, you should accept raw pointers.
Is this method of passing and storing this to a child object still considered 'acceptable' when using C++17, or is there a more appropriate method, in line with the language and standard?
I am specifically asking regarding passing and storing the Parent object as a plain pointer.
class Child
{
public:
void SetParent(Parent* p)
{
_parent = p;
}
private:
Parent* _parent;
};
class Parent
{
public:
void MyMethod()
{
Child c;
c.SetParent(this);
}
};
Post-C++11 you can use std::weak_ptr<Parent>, assuming you're using std::shared_ptr<Parent> (and inherit from std::enable_shared_from_this in order to generate a std::shared_ptr or std::weak_ptr internally).
Aside from that, yes, it's still acceptable to use a raw pointer to represent lack of ownership or back pointer (until the committee adds some kind of std::owned_ptr<T> / std::ptr_view<T> class).
I am currently trying to learn how to use smart pointers. However while doing some experiments I discovered the following situation for which I could not find a satifying solution:
Imagine you have an object of class A being parent of an object of class B (the child), but both should know each other:
class A;
class B;
class A
{
public:
void addChild(std::shared_ptr<B> child)
{
children->push_back(child);
// How to do pass the pointer correctly?
// child->setParent(this); // wrong
// ^^^^
}
private:
std::list<std::shared_ptr<B>> children;
};
class B
{
public:
setParent(std::shared_ptr<A> parent)
{
this->parent = parent;
};
private:
std::shared_ptr<A> parent;
};
The question is how can an object of class A pass a std::shared_ptr of itself (this) to its child?
There are solutions for Boost shared pointers (Getting a boost::shared_ptr for this), but how to handle this using the std:: smart pointers?
There is std::enable_shared_from_this just for this purpose. You inherit from it and you can call .shared_from_this() from inside the class. Also, you are creating circular dependencies here that can lead to resource leaks. That can be resolved with the use of std::weak_ptr. So your code might look like this (assuming children rely on existence of parent and not the other way around):
class A;
class B;
class A
: public std::enable_shared_from_this<A>
{
public:
void addChild(std::shared_ptr<B> child)
{
children.push_back(child);
// like this
child->setParent(shared_from_this()); // ok
// ^^^^^^^^^^^^^^^^^^
}
private:
// note weak_ptr
std::list<std::weak_ptr<B>> children;
// ^^^^^^^^
};
class B
{
public:
void setParent(std::shared_ptr<A> parent)
{
this->parent = parent;
}
private:
std::shared_ptr<A> parent;
};
Note however, that calling .shared_from_this() requires that this is owned by std::shared_ptr at the point of call. This means that you cannot create such object on stack anymore, and generally cannot call .shared_from_this() from within a constructor or destructor.
You have several problems in you design, that seem to stem from you misunderstanding of smart pointers.
Smart pointers are used to declare ownership. You are breaking this by declaring that both the parents owns all children, but also that each child own it's parent. Both can't be true.
Also, you are returning a weak pointer in getChild(). By doing so, you are declaring that the caller shouldn't care about the ownership. Now this can be very limiting, but also by doing so, you must make sure that the child in question won't get destroyed while any weak pointers are still held, if you would use a smart pointer, it would get sorted out by itself.
And the final thing. Usually, when you are accepting new entities, you should usually accept raw pointers. Smart pointer can have their own meaning for swapping children between parents, but for general usage, you should accept raw pointers.
here are the classes which my question is about
class Graph {}
class SceneGraph : public Graph {}
class Node {
public:
virtual Node* getNode(int index) { return mNodeList[index]; }
protected:
vector<Node*> mNodeList;
Graph* mGraph;
}
class TransformationNode : public Node {
public:
TransformationNode* getNode(int index) { return static_cast<TransformationNode*> (mNodelist[index]); }
void _update() {
auto beg = mNodeList.begin();
auto end = mNodeList.end();
while (begin != end) {
TransformationNode* node = static_cast<TransformationNode*> (*beg);
node->_update();
}
}
private:
bool mUpdated;
SceneGraph* mGraph;
}
First of all, I want to talk about the problems I solved. They may helps others. And you can confirm me if I am right ^^
Can I override a function with a different return type ?
Node* getNode(int index) became TransformationNode* getNode(int index)
Yes as long as return types are covariant : http://www.tolchz.net/?p=33
Can I override a member ?
I don't know about overriding but a variable with the same name in the derived class will hide the one in the base class
And there is the problem I really want to get around some how
In the TransformationNode class I did many (IMHO) avoidable type casting from base class to derived one. I definitely know that all the elements in the mNodeList vector are TransformationNodes but to process mNodeList I have to type cast them.
The inheritance is correct I mean TransformationNode is a Node
mNodeList holds child nodes of the node and it can not have a copy in the derived class which holds typecasted version of Nodes
And finaly I can even use reinterpered_cast if static_cast is more costly. Can you inform me about cost of these operations ? are they really big performance issues ?
assert (dynamic_cast)... kind of precaution has already been taken.
briefly I want my compiler to know that mGraph is actually a SceneGraph* and mNodeList holds TransformationNode* this helps me to avoid lost of type casting.
Thank you for taking your time
1) is correct, you can indeed override (virtual!) base functions if the return type is more derived.
Ad 2): indeed, you cannot "override" members. Redesign the base class if you need more flexible overridable behaviour.
static_cast is a static operation that is resolved at compile time, so much like reinterpret_cast it doesn't have any "cost".
As #Seth suggests in the comment, it might be an option to move the container. Ask yourself, can there ever be an abstract Node, or is every node actually of some derived concrete type? Perhaps you could make Node abstract:
struct Node { Node * getNode(size_t index) const = 0; };
struct TransformNode : Node
{
TransformNode * getNode(size_t index) const { return m_nodes[index]; }
private:
std::vector<TransformNode *> m_nodes;
};
Put the entire interface into the base class, but only implement it in each concrete class.