尝试在另一个头文件中的一个头文件中使用一个类

时间:2015-08-20 20:49:29

标签: c++ compiler-errors header-files

我在自己的头文件RICHDirectedGraph.h中有一个weightedDirectedGraph类和一个vertex类。就是这样:

#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

我在minHeapVertex.h文件中有一个minHeapVertex类,它将用作Dijkstra算法中的优先级队列。这是文件:

#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

我得到了很多编译错误(第一个是getMinVertex()声明中的C2143错误)我认为它可能与尝试访问minHeapVertex中的vertex类有关。 h。有人可以告诉我我做错了什么吗?试了几个小时,试着向前声明顶点类,尝试删除一些包含“”,查找错误代码并改变了一些东西,但没有任何工作只是结束了一堆错误。

1 个答案:

答案 0 :(得分:2)

问题:

OP在minHeapVertex.h和weightedDirectedGraph.h之间存在循环依赖。

解决方案:

消除依赖性。

minHeapVertex.h定义了minHeapVertex。 minHeapVertex需要顶点。

weightedDirectedGraph.h定义了vertex和weightedDirectedGraph。既不需要minHeapVertex。

此时有三种可能性:

  1. 将顶点旋转到自己的vertex.h标头中。 minHeapVertex.h和weightedDirectedGraph.h都包含vertex.h而不是彼此。

  2. weightedDirectedGraph.h不需要minHeapVertex.h,因此从weightedDirectedGraph.h中删除#include "minHeapVertex.h"以打破圆圈。

  3. 在minHeapVertex.h中定义class vertex;并从minHeapVertex.h中删除#include "weightedDirectedGraph.h"

  4. 溶液1是优选的。为顶点提供自己的标头可以防止将来出现问题。 2最容易实现。 3非常愚蠢,不推荐。

    为什么循环依赖会阻止minHeapVertex看到顶点:

    为了便于查看,我已从头文件中删除了所有其他包含。

    这是我的愚蠢小test.cpp

    #include "weightedDirectedGraph.h"
    
    int main(int argc, char * argsv[])
    {
      return 0;
    }
    

    编译器会生成一个test.cpp的临时文件。然后它将开始解析,直到找到include指令。将包含的文件复制粘贴到include语句的临时文件中。所以临时文件看起来像这样:

    #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;
    }
    

    编译器进一步解析并查看minHeapVertex.h和copy-paste的包含,以便得到这个:

    #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;
    }
    

    将其解析为#include "weightedDirectedGraph.h",但幸运的是GRAPH已定义,因此大多数weightedDirectedGraph.h都被遗漏了。如果还没有,那么RICHDirectedGraph.h中的所有东西都会被再次定义,并且minHeapVertex.h会再次被一次又一次地包含在内,最终编译器会崩溃或者告诉你 expletive deleted off礼貌的措辞错误信息。

    无论如何,我们已经可以看到上面的代码跟踪出了什么问题:minHeapVertex需要知道类型vertex,但是不会为另外20行左右定义。

    如果test.cpp已写为

    #include "minHeapVertex.h"
    
    int main(int argc, char * argsv[])
    {
      return 0;
    }
    

    头文件将被包含在另一个订单中并且它将被编译,给出一种错误的安全感,直到有一天你编写了一个首先包含weightedDirectedGraph.h的程序。换句话说,库可以工作,直到它没有,并且您没有更改库代码的一行。把头发拉出来玩得很开心。

    避免循环依赖,循环引用和圆锯。这三个人都可以把你扯得很糟糕。

    On using namespace std;这个邪恶的小捷径在std命名空间中占用一切,并将其添加到全局命名空间。如果你有一个名为reverse的函数,那么现在你必须处理与std :: reverse的潜在重载冲突。标准库很庞大。有大量的函数,类和变量名称只是需要重载,覆盖并且只是简单地践踏你的东西。

    但那是你的问题。

    using namespace std;放入标题会使每个人都遇到问题。任何使用你的图形库的人都必须趟过一个雷区,除非他们仔细查看你的头文件并看到这个声明,否则他们就不会有任何线索。

    Longer discussion can be found here.显式命名所有内容(std :: vector,std :: string,...)或仅提取您需要的部分,并且知道不会与using的代码冲突。例如:

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

    不要把它放在你的标题中,或者有人可能会想知道为什么他们的自制矢量吓坏了。可能不应该是自制的载体,但你无法拯救每个人。