试图在另一个头文件中的一个头文件中使用 class

Trying to use a class in one header file in another header file

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

#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 class,它将用作 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

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 "",查找了错误代码并进行了更改,但没有任何效果,最后只是出现了一堆错误。

问题:

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

解决方案:

消除依赖。

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

weightedDirectedGraph.h 定义顶点和加权有向图。两者都不需要 minHeapVertex。

此时三种可能:

  1. 将顶点旋转成它自己的 vertex.h header。 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"

首选解决方案 1。给顶点它自己的 header 可能会防止将来出现问题。 2 最容易实现。 3 太蠢了,不推荐。

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

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

这是我的小白痴test.cpp

#include "weightedDirectedGraph.h"

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

编译器会制作一个test.cpp的临时文件。然后它将开始解析,直到找到包含指令。包含的文件在 include 语句中 copy-pasted 到临时文件中。所以临时文件看起来有点像这样:

#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-pastes 的包含,所以你得到:

#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 被排除在外。如果没有,weightedDirectedGraph.h 中的所有内容都将被再次定义,并且 minHeapVertex.h 将再次被一遍又一遍地包含,最终编译器会崩溃或告诉您 咒骂删除 以礼貌的错误信息关闭。

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

如果test.cpp写成

#include "minHeapVertex.h"

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

header 文件会包含在其他顺序中,并且它会被编译,给人一种错误的安全感,直到有一天你编写了一个首先包含 weightedDirectedGraph.h 的程序。换句话说,库会一直工作,直到它停止工作,并且您没有更改库中的一行代码。拉头发玩得开心。

避免循环依赖、循环引用和圆锯。这三个都可以把你撕成碎片。

继续 using namespace std; 这个邪恶的小捷径获取 std 命名空间中的所有内容并将其添加到全局命名空间。如果您有一个名为 reverse 的函数,现在您必须处理与 std::reverse 的潜在重载冲突。标准库很大。有大量的函数、class 和变量名,它们只是渴望重载、覆盖和简单地践踏你的东西。

但这就是你的问题了。

using namespace std; 放在 header 中使其成为每个人的问题。任何使用您的图形库的人都必须涉足雷区,除非他们仔细查看您的 header 文件并查看该声明,否则他们不会有丝毫线索。

Longer discussion can be found here. 要么显式命名所有内容(std::vector,std::string,...),要么只引入你需要的部分并且知道不会与你的代码冲突 using.例如:

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

不要把它放在你的 header 中,否则有人可能会想知道为什么他们的自制软件向量会出错。可能不应该是自制载体,但你不能拯救所有人。