views:

64

answers:

3

So suppose I have a tree class like this in c++

class Node{
    void addChild(Node*);
    /*obvious stuff*/
    protected:
        Node* parent;
        vector<Node*> children
}

class specialNode : public Node{
    void addChild(specialNode*);
    /*obvious stuff*/
    /*special stuff*/
}

Now whenever I access the children in specialTree, I obviously get Node*, not specialNode*.

But this specialNode* has member variables and functions that Node doesn't have.

I can force specialNode to only have take specialNode as children and otherwise break in compile time, but I still get Node* when accessing children/parent, and I have to cast it whenever I want to use special functions, even in specialNode functions.

Is there any clever, or just any better way to go about this? Other than literally casting every time?

A: 

Because addChild function in your child class is not polymorphism, make it virtual, but overloading functions across base/child members is not allowed, so we have to change the addChild parameter in the child class:

class Node{
    virtual void addChild(Node*);
    ...
}

class specialNode : public Node{
    virtual void addChild(Node*);
    ...
}

Now, it should work.


If you want to access to the childeren variable from the child class (specialNode class), you should cast it. For example:

specialNode* var = static_cast<specialNode*>(children[i]);

Since we declared addChild as a virtual function, then we should use dynamic_cast instead of static_cast if we aren't sure that children[i] is always an instance of specialNode class, and thus it is better to use dynamic_cast:

specialNode* var = dynamic_cast<specialNode*>(children[i]);
if(var != NULL)
{
    //...
}
PC2st
Thanks for your answer..but not exactly what the question was about.Also, I'm pretty sure addChild(specialNode*) would just cover the scope of addChild(node*)
jaehoony
A: 

You will definitely have to cast the Node * to a specialNode * at some point, but you can make this clean and easy to manage by doing this in only one place. You could add a member function, say getParent and override it in specialNode, like this:

class Node {
  ...
  virtual Node *getParent() {
    return parent;
  }
};

class specialNode : public Node {
  ...
  specialNode *getParent() {
    return dynamic_cast<specialNode *>(parent);
  }
};

Of course, this is assuming that specialNodes always have other specialNodes as parent/children. If you mix Nodes and specialNodes, this obviously won't work.

casablanca
You'll run into troubles if you define two otherwise identical functions with different return type (there are two `getParent` methods which only differ by the type of their return value)
MartinStettner
@MartinStettner: Have a look at [Covariant Return Types in C++](http://www.lwithers.me.uk/articles/covariant.html) - this is allowed in the case of derived classes.
casablanca
@casablanca You're right, I was wrong, sorry.
MartinStettner
+4  A: 

If you only need SpecialNode objects in your tree (and just want to encapsulate all generic tree functionality in Node) you can make Node a so called "mix-in" class like

template <class N>
class Node : public N {
public:
  void addChild(Node<N>*);
protected:
  Node<N>* parent;
  vector<Node<N>*> children;
};

class SpecialNodeBase {
  // Here comes all "special" data/methods for your "special" tree
};

typedef Node<SpecialNodeBase> SpecialNode;

After that you can construct a tree of SpecialNode objects and use all methods from SpecialNodeBase as well as additional tree-managing functions from Node

MartinStettner
Wow...that's pretty sweet. Exactly what I was looking for. Thank you.
jaehoony
I might point out that by doing this, you've effectively defeated the purpose of inheritance - `SpecialNode` is no longer derived from `Node`, instead you end up creating independent classes with the same set of member variables.
casablanca
I also was about to point out this 'inversion of inheritance' :). In fact, mix-ins can be used to model orthogonal (cross-cutting) features, for which inheritance would be suboptimal: Suppose you want to organize cars and persons in a tree. Neither cars nor persons 'are a' Node (which inheritance would mean). Using a `Node<Car>` resp. `Node<Person>` notion could be read as "Node of Car" and "Node of Person" which is imo more appropriate to this situation.
MartinStettner
Note that the first version had an error: You have to use `Node<N>*` for `parent`, `children` and `addChild` (instead of `N*`)
MartinStettner
In your example `Node` is a generic container for other objects - in that case, it's fine. I thought the OP's `specialNode` was a specialization of `Node` itself, since he also mentioned a `specialTree`.
casablanca
Yeah, like Casablanca said, I did want a specialization of Node itself. I answered little too soon I think. I guess there's no perfect way around this. :(
jaehoony
If you have mixed objects (i.e. "ordinary" Nodes as well as "SpecialNode" nodes) in your tree, you'll have at least one special node which has a "normal" `Node` either as parent or as child. Therefore you'll have to do the cast anyway. As I tried to explain, my solution is for the case where you want the tree-related functions inside a `Node` class and want to define different trees with different type of nodes (but each tree having only one single type).
MartinStettner