Possible to avoid downcasting?

Steven Schveighoffer schveiguy at gmail.com
Thu Dec 26 17:05:01 UTC 2019


On 12/24/19 2:52 PM, H. S. Teoh wrote:
> I have a function makeTree() that builds a binary tree of BaseNode:
> 
> 	class BaseNode {
> 		BaseNode* left, right;
> 	}
> 	BaseNode makeTree() {
> 		auto node = new BaseNode(...);
> 		...
> 		return node;
> 	}
> 
> But I want to have the option of creating the tree with derived class
> nodes instead of BaseNode.  One option is to pass a factory function to
> makeTree():
> 
> 	BaseNode makeBaseNode() { return new BaseNode(...); }
> 	BaseNode makeTree(BaseNode function() makeNode = makeBaseNode) {
> 		auto node = makeNode();
> 		...
> 		return node;
> 	}
> 
> 	auto tree1 = makeTree(); // tree of BaseNodes
> 
> 	class Derived : BaseNode { ... }
> 	auto tree2 = makeTree(() => new Derived); // tree of Derived nodes
> 
> So far so good.  But now I want to iterate over the trees, and I'd like
> to be able to use information in the Derived node directly. But since
> makeTree() returns BaseNode, the only way I can get at the Derived nodes
> is to cast every node to Derived.  Furthermore, casting to Derived does
> not change the types of .left and .right, so this cast has to be done
> *every time*.

If you *know* all the types are the same, you can use reinterpret 
casting instead of downcasting, which basically will avoid the runtime 
checks.

e.g.:

auto realNode = cast(Derived)(cast(void*)node);

Now, aside from that, D does support covariance on virtual functions. 
Which can make things more pleasant

So...

class BaseNode
{
    BaseNode _left;
    BaseNode _right;
    BaseNode left() { return _left; }
    BaseNode right() { return _right; }
}

class Derived : BaseNode
{
    override Derived left() { return cast(Derived)cast(void*)_left; }
    override Derived right() { return cast(Derived)cast(void*)_right; }
}

Now, if you know you have a Derived, the left and right properties turn 
into Derived as well.

-Steve


More information about the Digitalmars-d mailing list