Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to handle unknown types in a C++ structure?

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?

like image 480
kdani Avatar asked Nov 29 '12 14:11

kdani


2 Answers

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.

like image 117
John Dibling Avatar answered Sep 21 '22 14:09

John Dibling


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.

like image 42
andre Avatar answered Sep 22 '22 14:09

andre