5

I am relatively new to C++, and facing a circular dependency problem. Can someone please help me solve this?

I have two classes:

class Vertex {
    string name;
    int distance;
    //Vertex path;
    int weight;
    bool known;
    list<Edge> edgeList;
    list<Vertex> adjVertexList;

public:
    Vertex();
    Vertex(string nm);
    virtual ~Vertex();
};

class Edge {
    Vertex target;
    int weight;

public:
    Edge();
    Edge(Vertex v, int w);
    virtual ~Edge();

    Vertex getTarget();
    void setTarget(Vertex target);
    int getWeight();
    void setWeight(int weight);
};

The above code gives following errors:

  • ‘Vertex’ does not name a type
  • ‘Vertex’ has not been declared
  • expected ‘)’ before ‘v’

How do I fix this problem?

AnilJ
  • 1,951
  • 2
  • 33
  • 60
  • 3
    Read this: http://stackoverflow.com/questions/553682/when-to-use-forward-declaration – BartoszKP Sep 22 '13 at 00:03
  • I'm not sure I understand what your `Vertex` is. Vertexes I usually think of don't have names and/or edges. – Shoe Sep 22 '13 at 00:19

2 Answers2

9

All you need is to forward-declare the Edge class before it's used within the Vertex:

class Edge;

class Vertex {
    string name;
    int distance;
    ...
};

class Edge { ... };

You can't put members of type Vertex instead of the declaration of Vertex itself, since C++ doesn't allow recursive types. Within the semantics of C++, the size of such type would need to be infinite.

You can, of course, put pointers to Vertex within Vertex.

What you want, in fact, within Vertex's edge and adjacency lists, is pointers, not copies of objects. Thus, your code should be fixed like below (assuming you use C++11, which you in fact should be using now):

class Edge;

class Vertex {
    string name;
    int distance;
    int weight;
    bool known;
    list<shared_ptr<Edge>> edgeList;
    list<shared_ptr<Vertex>> adjVertexList;

public:
    Vertex();
    Vertex(const string & nm);
    virtual ~Vertex();
};

class Edge {
    Vertex target;
    int weight;

public:
    Edge();
    Edge(const Vertex & v, int w);
    virtual ~Edge();

    Vertex getTarget();
    void setTarget(const Vertex & target);
    int getWeight();
    void setWeight(int weight);
};
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
2

If you think about it, instantiating a single Vertex or Edge object would instantiate an infinite amount of more Vertex and Edge objects because each of them contain instances of each other.

To fix this you need to forward declare a class, which one depends on the one you use first. Forward declaring classes allows you to use pointers and references to them without actually using the class, only pointing to it.

This snippet should be compilable but it will require some extra memory management.

class Edge; // This is a forward declaration

class Vertex {
    string name;
    int distance;
    //Vertex path;
    int weight;
    bool known;
    list<Edge*> edgeList;
    list<Vertex*> adjVertexList;

public:
    Vertex();
    Vertex(string nm);
    virtual ~Vertex();
};

class Edge {
    Vertex* target;
    int weight;

public:
    Edge();
    Edge(Vertex* v, int w);
    virtual ~Edge();

    Vertex* getTarget();
    void setTarget(Vertex* target);
    int getWeight();
    void setWeight(int weight);
};

This piece of code compiles because the classes now contain pointers to objects instead of the objects themselves.

As BartoszKP suggests you should read up on forward declarations and you might need to learn a bit more about pointers and references as well.


Since you are still having trouble I will update my answer with some more details. I read that you have actually split your classes into two header files now, I assume they are Vertex.h and Edge.h. They should look something like this

Vertex.h

class Edge;
class Vertex
{
    Edge* CreateEdge(); // Declaration of a class function
    // ...
};

Edge.h

class Vertex
class Edge
{
    // ...
};

You will need to include the complete definition of Edge when you want to use it for accessing its members or creating an instance. Basically you need to put the implementations of each function after all classes and structs have been defined. The easiest way to do this is by putting the function implementations in their respective .cpp file. It seems you want to create an Edge object from within the Vertex class, so you need to do that in your Vertex's .cpp file.

Vertex.cpp

#include "Vertex.h"
#include "Edge.h"

Edge* Vertex::CreateEdge()
{
    return new Edge();
}

Because the first thing done in this .cpp file is including the Vertex and Edge header files, that have their respective class definitions, you can completely use the Vertex and Edge classes as you want.

You will need a certain order in how you organize your declarations and definitions which goes like this

// Regarding global functions
Declaration    // void MyFunction();
Definition     // void MyFunction() { ... }

// Regarding classes and structs
Declaration    // class MyClass; - Forward declaration in another header file
Definition     // class MyClass { ... } - Definition in actual header file

// Regarding class functions
Declaration    // class MyClass { void MyFunction(); }
Definition     // void MyClass::MyFunction() { ... }
Community
  • 1
  • 1
FakeTruth
  • 135
  • 5
  • After some changes, I am seeing a new problem, which does not allow me to create an object of Edge in Vertex class where Edge is forward declared. In what way I will be able to create the Edge class object? It gives me an error - "invalid use of incomplete type ‘struct Edge’" – AnilJ Sep 22 '13 at 02:14