Problem:
OP 在 minHeapVertex.h 和 WeightedDirectedGraph.h 之间存在循环依赖关系。
解决方案:
消除依赖性。
minHeapVertex.h 定义 minHeapVertex。 minHeapVertex 需要顶点。
WeightedDirectedGraph.h 定义顶点和weightedDirectedGraph。两者都不需要 minHeapVertex。
此时三种可能:
-
将顶点旋转到其自己的 vertex.h 标头中。 minHeapVertex.h 和 WeightedDirectedGraph.h 都包含 vertex.h,但互不包含。
-
WeightedDirectedGraph.h 不需要 minHeapVertex.h,因此删除#include "minHeapVertex.h"
从加权有向图.h 打破循环。
-
前向定义class vertex;
在 minHeapVertex.h 中并删除#include "weightedDirectedGraph.h"
来自 minHeapVertex.h。
优选解决方案 1。为顶点提供自己的标头可以防止将来出现问题。 2最容易实现。 3非常愚蠢,不推荐。
为什么循环依赖会阻止 minHeapVertex 查看顶点:
为了使这一点更容易看到,我从头文件中删除了所有其他包含内容。
这是我愚蠢的小 test.cpp
#include "weightedDirectedGraph.h"
int main(int argc, char * argsv[])
{
return 0;
}
编译器将生成一个 test.cpp 的临时文件。然后它将开始解析,直到找到包含指令。包含的文件将复制粘贴到包含语句处的临时文件中。所以临时文件看起来有点像这样:
#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 和复制粘贴,因此您会得到以下结果:
#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 潜在的重载冲突。标准库很大。有大量的函数、类和变量名,它们只是渴望重载、覆盖和简单地践踏你的东西。
但这是你的问题。
Putting using namespace std;
在标题中使其成为每个人的问题。任何使用你的图形库的人都必须涉过雷区,除非他们仔细查看你的头文件并看到该声明,否则他们不会有丝毫线索。
可以在这里找到更长的讨论。要么显式命名所有内容(std::vector、std::string...),要么仅拉入您需要且知道不会与您的代码冲突的部分using
. Eg:
using std::vector;
using std::string;
不要将其放在标题中,否则有人可能会想知道为什么他们的自制向量会崩溃。也许不应该是自制载体,但你无法拯救所有人。