I'm writing an interpreter for a simple, Lisp-like programming language. It will process the code into nodes, all of them have types and some of them may have child nodes in an indexed order. Because of the difference in the nature of information, I can't use the same length of type for all node values. The name of their type is an enum type, but the only idea I have for the type of values is void *
. But when I use this, I must be very careful, I think. I mean, I can't use any default destructors, I must write a destructor that cares about the node type. Also I would have to use lots of casts even to access values.
This is what I'm talking about:
enum NodeType {/* Some node types */}
class Node
{
public:
Node(string input_code);
private:
NodeType type; // Having this I can know the type of value
void* value;
};
Is there a way that is more secure, makes a better code but is still as efficient as usage of void pointers?
There are two options I can think of. One is to use polymorphism, in which you have an abstract base class, Node
and a number of type-specific subclasses. Perhaps something like:
class Node
{
public:
virtual ~Node() = 0;
};
class String : public Node
{
public:
~String() {}
};
class Float : public Node
{
public:
~Float() {}
};
When storing these nodes, you would store Node*
rather than void*
. The presence of the (abstract) virtual destructor in the base class makes it possible to properly destroy concrete objects via the base class pointer, as with:
Node* obj = new String;
delete obj;
You can also call methods declared in the base class and have them execute code in the correct derived class, if those methods are virtual in the base class. these will often also be pure virtuals, such as with:
class Node
{
public:
std::string Speak() const = 0; // pure virt
};
class String : public Node
{
public:
std::string Speak() const { return "Hello"; }
};
Another option is to use some kind of variant class. C++ itself has no variant class built in to the language, but some libraries have been written such as Boost, which provide such a class.
Use inheritance/Interfaces:
struct BaseNode {
std::vector<BaseNode*> _children;
/*Some functions here*/
}
For each type
in the enum NodeType
make a new class which inherits BaseNode
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With