Luke Collins
Luke Collins

Reputation: 1463

Cyclic Pointers in C++

I am implementing a suffix trie structure in C++, where I use three classes, Trie, Node and Edge. Since I'm using classes, I've separated my function/variable declarations into header (.hpp) files and their implementations in respective .cpp files. Now I'm not used to doing this (I usually used to write everything in one .cpp file), but I think it is advantageous both for readability and structure.

So I have the following files:

Now the way I've implemented the trie is that each Node has a vector of type Edge. Additionally, I want that Edge has a pointer Node* so that it is pointing to another node (this is what edges do). Now although this seems like a cyclic definition, I recall that it can be achieved (at least, I used to be able to do this when my programs were all in one .cpp file).

But since we now have all these separate files with lots of #includes at the top, I have to #include 'Node.hpp' in Edge.hpp, and #include 'Edge.hpp' in Node.hpp. If I do not do this, I get errors such as "Edge is not defined in this scope". But if I do all the includes, I get an infinite-loop style error message:

enter image description here

The command I'm running is

g++ -std=c++11 -Wall -o program Edge.cpp Node.cpp Trie.cpp Launcher.cpp

I hope that's what I'm supposed to be running. Is there any way I can achieve what I want without these errors? I'm sure this would work if I put everything into one file.


EDIT: I have done the following in Edge.hpp, and everything seems to be working fine!

#ifndef EDGE_HPP
#define EDGE_HPP

#include <string>

class Node;         //Forward definition

using namespace std;

class Edge{

    private:
        string label;
        Node* pointsTo;

    public:
        Edge();
        Edge(string, Node*);
        string getLabel();
        Node* getPointsTo();

};

#endif

Upvotes: 2

Views: 845

Answers (1)

Sam Varshavchik
Sam Varshavchik

Reputation: 118445

This is a simple case of forward declaration.

Now the way I've implemented the trie is that each Node has a vector of type Edge.

This would be translated to something like this, in Node's header file:

class Edge;

class Node {

public:
    std::vector<Edge> edges;

    Node();
    ~Node();
};

This will be sufficient to declare the Node in its header file. Don't need to include Edge's header file.

Now, the .cpp file, that defines Node's constructor and destructor, must include both header files, so that both classes are fully declared.

Additionally, I want that Edge has a pointer Node* so that it is pointing to another node (this is what edges do).

And that simply translates to, in Edge's header file:

class Node;

class Edge {

public:
    Node *from_node;
    Node *to_node;

    // ...
};

Again, don't need to include Node's header file.

Having Node's header file include Edge's header file, instead of forward-declaring the class, would probably be fine too, with only Edge's header file needing to forward-declare the Node class.

The only thing you will need to keep in mind is that any code that needs to use the Edge class, and work with its Nodes, will need to include both header files. Merely including Edge will not be sufficient, since that code won't get the declaration of each Node, that the edge points to, unless Node's header file is also included.

Also, sometimes forward declarations might make it impossible to declare inline class methods, that need to use the forward-declared class. There are various ways around that, too.

Upvotes: 2

Related Questions