Right, that's a very simple tree implementation that simply allows for general splits (root/branch) and nodes with no data encapsulation capabilities. The true use of the nodes is meant to be defined by classes derived from these bases.
When I try to enumerate all of the nodes within a tree, as such:
1 2 3 4 5 6 7 8 9 10 11 12
template <typename BranchType>
inlinevoid enumerate_children_all (CBasicSequentialTreeSplit* pSplit, SequentialEnumerator enumerator, NodeType Filter = Tree_Mask)
{
for (auto iter = pSplit->_bsts_children->begin (); iter != pSplit->_bsts_children->end (); iter++)
{
if ((*iter)->_bto_type & Filter)
enumerator (*iter);
if ((*iter)->_bto_type & Tree_Split)
enumerate_children_all <BranchType> ((BranchType *)*iter, enumerator, Filter);
}
}
I always have to cast to BranchType, which, as the name implies, is the type of the actual branch object being passed. If I don't do this cast I get access violation errors when attempting to access children, but I don't completely understand why. I'm compiling using Visual C++ 2010; it would be greatly appreciated if anyone could explain this.
What is a CRetainablePtr<DEF_SEQUENTIAL_CONTAINER<CBasicSequentialTreeNode *>> ?
This is one example where I think auto is unhelpful. If the type was specified in the code, it'd be clear to readers of the code what the type is (and not just the compiler).
That specific part of the code is irrelevant, as the necessity to cast to the furthest derived class is apparently inherent no matter what the application is.
ne555 is correct in that it's just to make the appropriate cast. That function is part of a small library that performs general-purpose enumeration and traveral, and in order to access subnodes within a branch I have to make the "appropriate" cast to the derived class, as given by BranchType. Also, *iter is a CBasicSequentialTreeNode, which CBasicSequentialTreeBranch is derived from.
The question remains; Why am I getting violation access errors when I don't cast to the derived class?
I think the problem is that you ask for Split* but you pass a Node*
¿Is this equivalent?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
class A{};
class B{ //note that A and B are not related
public:
some_container<A *> container;
};
class C: public A, public B{};
void foo(B *root){
for(size_t K=0; K<root->container.size(); ++K){
// foo(root->container[K]); //error: cannot convert 'A*' to 'B*' for argument '1' to 'void foo(B*)'
foo( (C*) root->container[K] );
}
}
You may want to review your design. If you always are going to cast to C*, maybe then it should be some_container<C *> B::container;
If I don't do this cast I get access violation errors when attempting to access children
Wait, ¿runtime errors?. It should not compile without the casting. I'm confused.
It's equivalent, and I'm not always going to be casting to C. There are circumstances when a node will be treated as some derivative of B, but there can also be As. I'm not casting to a C unless I know that the object A is also a derivative of B, hence line 9.
ne555, it should, to my understanding, compile just fine, and it does. A derived from B, you can assign a pointer to an A to the address of a B. Right?
A derived from B, you can assign a pointer to an A to the address of a B. Right?
Yes, If A derived from B (the other way you need dynamic_cast).
But in the example, (and IIRC in your code too) A and B are not related. That is what you need to cast to B*
1 2 3 4 5 6 7
class CBasicSequentialTreeNode
: public CBasicTreeObject; // (A)
class CBasicSequentialTreeSplit; //base class (B)
class CBasicSequentialTreeBranch
: public CBasicSequentialTreeNode, public CBasicSequentialTreeSplit; //derived from both (C)
I'm not good in design, but you could try to avoid casting using polymorphism (if you have a common parent)
By instance
1 2 3 4 5 6 7 8 9 10
/* virtual */ inlinevoid CBasicSequentialTreeSplit::enumerate (SequentialEnumerator enumerator)
{
for (auto iter = _bsts_children->begin (); iter != _bsts_children->end (); iter++)
(*iter)->enumerate(enumerator);
}
/* virtual */ inlinevoid CBasicSequentialTreeNode::enumerate(SequentialEnumerator enumerator)
{
enumerator(*this);
}
Alright, I'm seeing it now. It was my interpretation of how the compiler used casting that made it difficult for me to understand your explanation, thanks for the help.