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

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

本文关键字:文件 一个 另一个      更新时间:2023-10-16

我有一个weightedDirectedGraph类和一个vertex类在他们自己的头文件,weightedDirectedGraph.h。

#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.h中的vertex类有关。谁能告诉我我哪里做错了?一直在它几个小时,尝试向前声明顶点类,尝试删除一些包括",查找错误代码和改变的东西,但没有工作,只是以一堆错误结束。

问题:

OP在minHeapVertex.h和weightedDirectedGraph.h之间有一个循环依赖。

<标题>解决方案:

消除依赖。

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

weightedDirectedGraph.h定义了顶点和加权directedgraph。都不需要minHeapVertex

目前有三种可能:

  1. 旋转顶点到自己的顶点。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" .

优先考虑解决方案1。给顶点一个自己的头可以防止将来的问题。2最容易实现。3是相当愚蠢的,不推荐。

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

为了更容易看到,我从头文件中删除了所有其他包含。

这是我愚蠢的小测试。

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

编译器将生成一个test.cpp的小临时文件。然后,它将开始解析,直到找到一个包含指令。包含的文件在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被省略了。如果没有,那么weightedDirectedGraph.h中的所有内容都将被重新定义,minHeapVertex.h将再次被一遍又一遍地包含,最终编译器将崩溃或告诉您删除并给出礼貌的错误消息。

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

如果test.cpp被写成

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

头文件将以另一种顺序包含,它将被编译,给人一种错误的安全感,直到有一天您编写的程序首先包含了weightedDirectedGraph.h。换句话说,库可以正常工作,直到它不能工作为止,并且您没有更改库的任何代码。祝你玩得开心。

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

On to using namespace std;这个邪恶的小快捷方式将std命名空间中的所有内容添加到全局命名空间中。如果有一个名为reverse的函数,现在必须处理与std::reverse的潜在重载冲突。标准库是巨大的。有大量的函数、类和变量名都想重载、覆盖和践踏你的东西。

但那是你的问题。

using namespace std;放在标题中使它成为每个人的问题。任何使用你的绘图库的人都必须穿过雷区,除非他们仔细查看你的头文件并看到那个声明,否则他们不会有丝毫的线索。

可以在这里找到更详细的讨论。要么显式地命名所有内容(std::vector, std::string,…),要么只拉入您需要并且知道的部分,这些部分不会与using的代码冲突。如:

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

不要把这个放在你的标题中,否则有人可能会想知道为什么他们的自制向量会崩溃。也许不应该是自制载体,但你不能拯救所有人。