What you are looking for is polymorphism. That is, code that a programmer writes, and does different things depending on the types of the things it operates on.
C++ supports a bewildering array of ways to do polymorphism.
The most supported kind is inheritance based virtual polymorphism. In this, you create a base class:
struct INode {
virtual ~INode() {}
};
and add in common operations to it, making those common operations pure-virtual:
struct INode {
virtual ~INode() {}
virtual std::vector<INode*> GetChildren() const = 0;
};
This requires that you work with pointers instead of object instances.
In this system, if you know the type of an object, you can use dynamic_cast<RealType*>(iNodePointer)
to get a pointer to the object as an instance of that type. It returns nullptr
if the types don't match. This lets you access the methods you have in the descended type that aren't in the base interface.
A second kind of polymorphism is std::variant
based. This is a closed set of types, which parsers often have.
using AnyNode = std::variant<Node::BinaryOp, Node::UnaryOp, Node::Number>;
here you use std::visit
to operate on the concrete type instead of dynamic_cast
, and your parse tree is value-based instead of pointer-based.
There is some pain when you want a node to have inside itself a vector of AnyNode
.
A third way is std::function
type-erasure style. Here you write your own polymorphic system that takes objects of arbitrary type and wraps their operations up in a value-semantics wrapper.
A forth option is CRTP static polymorphism. This isn't suitable to build a dynamic parse tree, but it can be used to help implement some of the above.
A fifth option is aspect oriented std::function
operation bundles.
A sixth option is manual function table tweaking, basically reimplementing the C++ vtable solution manually as if you are in C, but in C++. This can permit you to have features similar to other OO-languages.
A seventh option is to write up a signals-slots system and send messages to your objects.
There are almost certainly more.
The easiest solution is probably to first learn about inheritance and virtual functions in C++ (the first option above). I personally would probably write a parse tree using std::variant
at this point, but if you probably don't know enough C++ at this point to practically do that.