Search code examples
c++visual-studio-2017header-filescircular-dependency

Classes in different headers do not recognize each other?


Even though the visual studio pre-compiler or whatever it's called recognizes Graph as a class from a different header, after building I get the most ridiculous errors acting as if I've never mentioned the other headers before. First I didn't forward declare both classes and the first set of errors below come from this, but then I tried forward declaring and there are similar errors related to the structure of the classes themselves. Using functions from another class produce them which shows me the header files do NOTHING. They don't know about each other's functions and I don't know why.

Vertex.h :

#pragma once
#include "Graph.h"
#include <vector>

class Graph;
class Vertex
{
    int unique_id;
    int longestChain = 0;
    int chainComponent_id;
    std::vector<int> edges;
    Graph* master;
public:
    int get_id()
    {
        return unique_id;
    }

    int getChainComponent_id()
    {
        return chainComponent_id;
    }

    void setChainComponent_id(int id)
    {
        chainComponent_id = id;
    }

    int DFS(int, int);

    Vertex(int id, std::vector<int> _edges, Graph* _master)
    {
        unique_id = id;
        edges = _edges;
        master = _master;
        longestChain = 0;
        chainComponent_id = -1;
    }
};

Graph.h :

#pragma once
#include "Vertex.h"
#include <vector>
#include <iostream>
class Vertex;
class Graph
{
    std::vector<Vertex*> vertex;
    int amountOfChainComponents = 0;
public:
    Vertex* getVertex(int id)
    {
        if(id<0 || id>vertex.size())
        {
            return nullptr; //shouldn't be possible with proper input
        }
        return vertex[id];
    }
    int getAmountOfChainComponents()
    {
        return amountOfChainComponents;
    }
    int longestChain()
    {
        int longest = 0;
        for(int i = 0; i < vertex.size(); i++)
        {
            if(vertex[i]->getChainComponent_id() == -1)
            {
                int tmp = vertex[i]->DFS(0, amountOfChainComponents);
                amountOfChainComponents++;
                if(tmp > longest)
                {
                    longest = tmp;
                }
            }
        }
        if(longest == -1)
        {
            std::cout << "There is a chain for every positive integer" << std::endl;
            return -1;
        }
        if(longest < 2)
        {
            std::cout << "There is no chain" << std::endl;
            return 0;
        }

        return longest;

    }
    Graph(std::vector<std::vector<int>> vertices)
    {
        amountOfChainComponents = 0;
        for(int i = 0; i < vertices.size(); i++)
        {
            Vertex* tmp = new Vertex(i, vertices[i], this);
            vertex.push_back(tmp);
        }
    }
    ~Graph()
    {
        while(!vertex.empty())
        {
            delete vertex[vertex.size() - 1];
            vertex.pop_back();
        }
    }
};

Line Severity Description File 11 Error syntax error: missing ';' before '*' c:\users\bico\source\repos\longestchaingraph\longestchaingraph\vertex.h 34 Error '_master': undeclared identifier c:\users\bico\source\repos\longestchaingraph\longestchaingraph\vertex.h 11 Error missing type specifier - int assumed. Note: C++ does not support default-int c:\users\bico\source\repos\longestchaingraph\longestchaingraph\vertex.h 11 Error unexpected token(s) preceding ';' c:\users\bico\source\repos\longestchaingraph\longestchaingraph\vertex.h 30 Error syntax error: identifier 'Graph' c:\users\bico\source\repos\longestchaingraph\longestchaingraph\vertex.h 34 Error 'master': undeclared identifier c:\users\bico\source\repos\longestchaingraph\longestchaingraph\vertex.h Line Severity Description File 8 Error 'Vertex': undeclared identifier c:\users\bico\source\repos\longestchaingraph\longestchaingraph\graph.h

Errors that come after forward declaration:

Line Severity Description File 28 Error use of undefined type 'Vertex' c:\users\bico\source\repos\longestchaingraph\longestchaingraph\graph.h 28 Error left of '->getChainComponent_id' must point to class/struct/union/generic type c:\users\bico\source\repos\longestchaingraph\longestchaingraph\graph.h 30 Error use of undefined type 'Vertex' c:\users\bico\source\repos\longestchaingraph\longestchaingraph\graph.h 30 Error left of '->DFS' must point to class/struct/union/generic type c:\users\bico\source\repos\longestchaingraph\longestchaingraph\graph.h 57 Error use of undefined type 'Vertex' c:\users\bico\source\repos\longestchaingraph\longestchaingraph\graph.h


Solution

  • This is a circular dependency issue; the two header files are including each other.

    For both cases, only forward declaration will be enough; declare a pointer to class doesn't need the class to be complete type.

    Vertex.h

    #pragma once
    #include <vector>
    
    class Graph;
    class Vertex
    {
        int unique_id;
        int longestChain = 0;
        int chainComponent_id;
        std::vector<int> edges;
        Graph* master;
    };
    

    Graph.h

    #pragma once
    #include <vector>
    #include <iostream>
    
    class Vertex;
    class Graph
    {
        std::vector<Vertex*> vertex;
        int amountOfChainComponents = 0;
    };
    

    EDIT

    Move member functions' implementations to implementation files. e.g.

    Vertex.h

    #pragma once
    #include <vector>
    
    class Graph;
    class Vertex
    {
        int unique_id;
        int longestChain = 0;
        int chainComponent_id;
        std::vector<int> edges;
        Graph* master;
    public:
        int get_id();
        ...
    };
    

    Vertex.cpp

    #pragma once
    #include "Vertex.h"
    #include "Graph.h"
    
    int Vertex::get_id()
    {
        return unique_id;
    }
    ...
    

    Graph.h

    #pragma once
    #include <vector>
    #include <iostream>
    
    class Vertex;
    class Graph
    {
        std::vector<Vertex*> vertex;
        int amountOfChainComponents = 0;
    public:
        Vertex* getVertex(int id);
        ...
    };
    

    Graph.cpp

    #pragma once
    #include "Vertex.h"
    #include "Graph.h"
    
    Vertex* Graph::getVertex(int id)
    {
        if(id<0 || id>vertex.size())
        {
            return nullptr; //shouldn't be possible with proper input
        }
        return vertex[id];
    }
    ...
    

    EDIT2

    As @M.M pointed, forward declaration is enough for class Graph in Vertex.h. So you can just remove #include "Graph.h" in Vertex.h, and reserve #include "Vertex.h" in Graph.h.