1

I have a weightedDirectedGraph class and a vertex class in their own header file, weightedDirectedGraph.h. This is it:

#ifndef GRAPH
#define GRAPH

#include <iostream>
#include <string>
#include <vector>
#include <list>
#include "minHeapVertex.h"
using namespace std;

class vertex
{
public:
    string data;
    list<vertex *> neighbors;
    bool known;
    int distance, id;
    vertex * path;

    vertex(string x)
    {
        data = x;
    }
};

class weightedDirectedGraph
{
private:
    list<vertex *> vertexList;
    vector<vector<int> > edgeWeights;   //2D vector to store edge weights
    int idCount;

    weightedDirectedGraph()
    {
        idCount = 0;
    }

    vertex * findVertex(string s);
    void dijkstrasAlg(vertex * s);

public:
    void addVertex(string x);

    //adds bi-directional edges
    void addWeightedEdge(string x, string y, int weight);
};

#endif

And I have a minHeapVertex class in a minHeapVertex.h file that will be used as a priority queue in Dijkstra's algorithm. This is the file:

#ifndef MIN_HEAP_VERTEX
#define MIN_HEAP_VERTEX

#include <iostream>
#include <vector>
#include "weightedDirectedGraph.h"
using namespace std;

class minHeapVertex
{
public:
    explicit minHeapVertex(int capacity = 100)
        :heapArray(capacity + 1), currentSize{ 0 } {}

    bool isEmpty() const
    {
        return (currentSize == 0);
    }

    vertex * getMinVertex() const;  //getting C2143 error here that says I'm missing a semi-colon before '*'. Doesn't make sense though.
    void insert(vertex * insertItem);
    void deleteMin();                   
    vertex * deleteAndReturnMin();      
    void makeEmpty()
    {
        currentSize = 0;
    }
    void decreaseKey(int index, int decreaseValue);
    void remove(int index);

private:
    void buildHeap();
    void percolateDown(int hole);

    vector<vertex *> heapArray;
    int currentSize;
};
#endif

I"m getting a lot of compiling errors (with the first one being a C2143 error on the getMinVertex() declaration) and I think it may have something do with trying to access the vertex class in minHeapVertex.h. Can someone show me what I'm doing wrong? Been at it for hours, tried forward declaring the vertex class, tried removing some of the includes "", looked up the error codes and changed things, but nothing is working and just end up with a bunch of errors.

David Velasquez
  • 2,346
  • 1
  • 26
  • 46
  • 1
    *"I"m getting a lot of compiling errors"* ... and those would be? – Cory Kramer Aug 20 '15 at 20:51
  • 3
    Remove `include "minHeapVertex.h"` – Galimov Albert Aug 20 '15 at 20:53
  • @CoryKramer There are 77 errors. I posted the first one since that one usually is the main problem. I'm hoping someone more experienced can examine the code and notice something wrong. It's just a bunch of class definitions, so I'm not expecting any logical errors, just syntax errors. – David Velasquez Aug 20 '15 at 20:55
  • @PSIAlt But won't I need it when I want to make a minHeapVertex object in the definition of Dijkstra's algorithm? – David Velasquez Aug 20 '15 at 20:56
  • 1
    Recommend removing the `using namepace std;` from the headers. You may not behaving trouble with it now, but sooner or later you probably will. And it will be a sneaky problem. On the main topic, give this a read: http://stackoverflow.com/questions/4757565/c-forward-declaration – user4581301 Aug 20 '15 at 21:03
  • Ghost_Stark, you will need minHeapVertex.h, more than likely, but @PSIAlt is right. weightedDirectedGraph.h does not need it, and it's causing a circular dependency in your header files. A includes B which includes A which includes B ... The header guards are doing their job and keeping the recursion from getting out of hand, but it allows for other equally icky possibilities. – user4581301 Aug 20 '15 at 21:10
  • 1
    Please don't put `using namespace std;` in the global namespace of a header file (or, preferably, anywhere at all): https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice – Galik Aug 20 '15 at 21:14
  • @user4581301 I don't understand why you say I'll need it but to remove it. – David Velasquez Aug 20 '15 at 21:23
  • Working on an answer to demonstrate what is happening. – user4581301 Aug 20 '15 at 21:23

1 Answers1

3

Problem:

OP has a circular dependency between minHeapVertex.h and weightedDirectedGraph.h.

Solution:

Eliminate the dependency.

minHeapVertex.h defines minHeapVertex. minHeapVertex requires vertex.

weightedDirectedGraph.h defines vertex and weightedDirectedGraph. Neither require minHeapVertex.

Three possibilities at this point:

  1. Spin vertex off into its own vertex.h header. minHeapVertex.h and weightedDirectedGraph.h both include vertex.h and not each other.

  2. weightedDirectedGraph.h does not require minHeapVertex.h, so remove #include "minHeapVertex.h" from weightedDirectedGraph.h to break the circle.

  3. forward definition of class vertex; in minHeapVertex.h and the removal of #include "weightedDirectedGraph.h" from minHeapVertex.h.

Solution 1 is preferred. Giving vertex its own header may prevent future problems. 2 is easiest to implement. 3 is pretty stupid and not recommended.

Why circular dependency prevented minHeapVertex from seeing vertex:

To make this easier to see, I've removed all of the other includes from the header files.

Here's my idiotic little test.cpp

#include "weightedDirectedGraph.h"

int main(int argc, char * argsv[])
{
  return 0;
}

The compiler will make a little temp file of test.cpp. It will then start parsing until it finds an include directive. The included file is copy-pasted into the temp file at the include statement. So the temp file looks sort of like this:

#define GRAPH

#include "minHeapVertex.h"
using namespace std;

class vertex
{
public:
    string data;
    list<vertex *> neighbors;
    bool known;
    int distance, id;
    vertex * path;

    vertex(string x)
    {
        data = x;
    }
};

class weightedDirectedGraph
{
private:
    list<vertex *> vertexList;
    vector<vector<int> > edgeWeights;   //2D vector to store edge weights
    int idCount;

    weightedDirectedGraph()
    {
        idCount = 0;
    }

    vertex * findVertex(string s);
    void dijkstrasAlg(vertex * s);

public:
    void addVertex(string x);

    //adds bi-directional edges
    void addWeightedEdge(string x, string y, int weight);
};


int main(int argc, char * argsv[])
{
  return 0;
}

The compiler parses down a little further and sees the include of minHeapVertex.h and copy-pastes so you get this:

#define GRAPH

#define MIN_HEAP_VERTEX

#include "weightedDirectedGraph.h"
using namespace std;

class minHeapVertex
{
public:
    explicit minHeapVertex(int capacity = 100)
        :heapArray(capacity + 1), currentSize{ 0 } {}

    bool isEmpty() const
    {
        return (currentSize == 0);
    }

    vertex * getMinVertex() const;  //getting C2143 error here that says I'm missing a semi-colon before '*'. Doesn't make sense though.
    void insert(vertex * insertItem);
    void deleteMin();
    vertex * deleteAndReturnMin();
    void makeEmpty()
    {
        currentSize = 0;
    }
    void decreaseKey(int index, int decreaseValue);
    void remove(int index);

private:
    void buildHeap();
    void percolateDown(int hole);

    vector<vertex *> heapArray;
    int currentSize;
};

using namespace std;

class vertex
{
public:
    string data;
    list<vertex *> neighbors;
    bool known;
    int distance, id;
    vertex * path;

    vertex(string x)
    {
        data = x;
    }
};

class weightedDirectedGraph
{
private:
    list<vertex *> vertexList;
    vector<vector<int> > edgeWeights;   //2D vector to store edge weights
    int idCount;

    weightedDirectedGraph()
    {
        idCount = 0;
    }

    vertex * findVertex(string s);
    void dijkstrasAlg(vertex * s);

public:
    void addVertex(string x);

    //adds bi-directional edges
    void addWeightedEdge(string x, string y, int weight);
};


int main(int argc, char * argsv[])
{
  return 0;
}

That gets parsed down to #include "weightedDirectedGraph.h", but fortunately GRAPH has been defined, so most of weightedDirectedGraph.h gets left out. If it hadn't, Everything in weightedDirectedGraph.h would have been defined again and minHeapVertex.h would once again been included over and over and eventually the compiler would crash or tell you to expletive deleted off with a politely worded error message.

Anyway, we can already see what's gone wrong in the above code trace: minHeapVertex needs to know type vertex, but that won't be defined for another 20 lines or so.

If test.cpp had been written as

#include "minHeapVertex.h"

int main(int argc, char * argsv[])
{
  return 0;
}

The header files would have been included in the other order and it would have compiled, giving a false sense of security until one day you wrote a program that included weightedDirectedGraph.h first. In other words, the library works until it doesn't, and you didn't change a line of the library's code. Have fun pulling your hair out.

Avoid circular dependencies, circular references and circular saws. All three can rip you up pretty bad.

On to using namespace std; This evil little shortcut takes EVERYTHING in the std namespace and adds it to the global namespace. If you had a function named reverse, now you have to deal with potential overload conflicts with std::reverse. The standard library is huge. There are a huge number of function, class, and variable names that are just itching to overload, override and just plain trample your stuff.

But that's your problem.

Putting using namespace std; in a header make it everyone's problem. Anyone who uses your graphing library has to wade through a minefield, and unless they take a close look at your header file and see that declaration they won't have the slightest clue.

Longer discussion can be found here. Either explicitly namespace everything (std::vector, std::string, ...) or pull in only the pieces you need and know will not conflict with your code with using. Eg:

using std::vector;
using std::string;

Do not put this in your header or someone may wind up wonder why their homebrew vector is freaking out. Probably shouldn't be homebrewing vectors, but you can't save everybody.

Community
  • 1
  • 1
user4581301
  • 33,082
  • 7
  • 33
  • 54
  • Thanks for writing all of this. Very helpful. And you're right in that `minHeapVertex` needs to know type `vertex`. How do I get it to know that type? Nothing I'm doing is working. – David Velasquez Aug 21 '15 at 01:56
  • @Ghost_Stark .Wow. Can't believe I left that out. Seriously sorry about that. Edited answer. – user4581301 Aug 21 '15 at 04:22
  • I appreciate all this very much. Just one more question. I will probably go with solution 1, but for solution 2 you say weightedDirectedGraph.h does not require minHeapVertex.h. But I will be creating a minHeapVertex object inside the definition of Dijkstra's algorithm. Doesn't that imply weightedDirectedGraph.h will require minHeapVertex.h? I ask because I tried this solution, and then I get errors in minHeapVertex.h where every use of the class `vertex` shows an error saying `vertex` is undefined. – David Velasquez Aug 21 '15 at 05:59
  • @Ghost_Stark The dijkstrasAlg method doesn't have to be implemented inside the header file, so the header doesn't have to know minHeapVertex. The cpp file containing the implementation of dijkstrasAlg does need to know and can include both minHeapVertex.h and weightedDirectedGraph.h without any problems, assuming you don't make the oft-fatal mistake of including a cpp file. It's only when you build a circle in the includes that you start having problems. A header should include everything it needs so it is stand-alone, but should only include what it needs. No more, no less. – user4581301 Aug 21 '15 at 07:12
  • recap: weightedDirectedGraph.cpp includes weightedDirectedGraph.h and then minHeapVertex.h. weightedDirectedGraph.h includes nothing but what it requires from the standard library. minHeapVertex.h includes what it needs from the standard library and weightedDirectedGraph.h to get he definition of vertex. Actually, weightedDirectedGraph.cpp only needs to include minHeapVertex.h because minHeapVertex.h already includes weightedDirectedGraph.h, but it will look odd without including it's own header directly. – user4581301 Aug 21 '15 at 07:25
  • Ah okay, I understand. I was putting the member definitions in the same header file. I wasn't using a cpp file. Since this code won't be distributed and will only be used by me, I didn't use separate cpp files. But now I see how using separate cpp files for class member definitions can be very important. Anyways, I used the first solution and it worked perfectly. Thanks for your time typing out the detailed explanation. – David Velasquez Aug 21 '15 at 07:50