C++类中的循环依赖关系

Circular dependency in C++ classes

本文关键字:依赖 关系 循环 C++      更新时间:2023-10-16

我对C++相对较新,并且面临循环依赖问题。有人可以帮我解决这个问题吗?

我有两个类:

class Vertex {
    string name;
    int distance;
    //Vertex path;
    int weight;
    bool known;
    list<Edge> edgeList;
    list<Vertex> adjVertexList;
public:
    Vertex();
    Vertex(string nm);
    virtual ~Vertex();
};
class Edge {
    Vertex target;
    int weight;
public:
    Edge();
    Edge(Vertex v, int w);
    virtual ~Edge();
    Vertex getTarget();
    void setTarget(Vertex target);
    int getWeight();
    void setWeight(int weight);
};

上面的代码给出了以下错误:

  • "顶点"不命名类型
  • "顶点"尚未声明
  • 在"v"之前应为")"

如何解决此问题?

您所需要的只是在Edge类在Vertex中使用之前转发声明它:

class Edge;
class Vertex {
    string name;
    int distance;
    ...
};
class Edge { ... };

不能放置类型 Vertex 的成员而不是Vertex本身的声明,因为C++不允许递归类型。在C++的语义中,这种类型的大小需要是无限的。

当然,您可以在Vertex内放置指向Vertex的指针。

事实上,在Vertex的边缘和邻接列表中,你想要的是指针,而不是对象的副本。因此,您的代码应该像下面这样修复(假设您使用C++11,实际上您现在应该使用它):

class Edge;
class Vertex {
    string name;
    int distance;
    int weight;
    bool known;
    list<shared_ptr<Edge>> edgeList;
    list<shared_ptr<Vertex>> adjVertexList;
public:
    Vertex();
    Vertex(const string & nm);
    virtual ~Vertex();
};
class Edge {
    Vertex target;
    int weight;
public:
    Edge();
    Edge(const Vertex & v, int w);
    virtual ~Edge();
    Vertex getTarget();
    void setTarget(const Vertex & target);
    int getWeight();
    void setWeight(int weight);
};

如果您考虑一下,实例化单个VertexEdge对象将实例化无限数量的更多VertexEdge对象,因为它们中的每一个都包含彼此的实例。

要解决此问题,您需要转发声明一个类,哪个类取决于您首先使用的类。前向声明类允许您使用指针和对它们的引用,而无需实际使用该类,而仅指向它。

此代码段应该是可编译的,但它需要一些额外的内存管理。

class Edge; // This is a forward declaration
class Vertex {
    string name;
    int distance;
    //Vertex path;
    int weight;
    bool known;
    list<Edge*> edgeList;
    list<Vertex*> adjVertexList;
public:
    Vertex();
    Vertex(string nm);
    virtual ~Vertex();
};
class Edge {
    Vertex* target;
    int weight;
public:
    Edge();
    Edge(Vertex* v, int w);
    virtual ~Edge();
    Vertex* getTarget();
    void setTarget(Vertex* target);
    int getWeight();
    void setWeight(int weight);
};

这段代码之所以可以编译,是因为类现在包含指向对象的指针,而不是对象本身。

正如BartoszKP建议的那样,您应该阅读前向声明,并且可能还需要了解有关指针和引用的更多信息。


由于您仍然遇到麻烦,我将用更多详细信息更新我的答案。我读到您现在实际上已将类拆分为两个头文件,我假设它们是Vertex.hEdge.h.它们应该看起来像这样

顶点

class Edge;
class Vertex
{
    Edge* CreateEdge(); // Declaration of a class function
    // ...
};

边缘.h

class Vertex
class Edge
{
    // ...
};

当您想要使用它来访问其成员或创建实例时,您需要包含Edge的完整定义。基本上,您需要将每个函数的实现放在定义所有类和结构之后。最简单的方法是将函数实现放在各自的.cpp文件中。似乎您想从Vertex类中创建一个Edge对象,因此您需要在Vertex.cpp文件中执行此操作。

顶点.cpp

#include "Vertex.h"
#include "Edge.h"
Edge* Vertex::CreateEdge()
{
    return new Edge();
}

由于在此.cpp文件中要做的第一件事是包括具有各自类定义的VertexEdge头文件,因此您可以根据需要完全使用 VertexEdge类。

在如何组织声明和定义时,您将需要一定的顺序,如下所示

// Regarding global functions
Declaration    // void MyFunction();
Definition     // void MyFunction() { ... }
// Regarding classes and structs
Declaration    // class MyClass; - Forward declaration in another header file
Definition     // class MyClass { ... } - Definition in actual header file
// Regarding class functions
Declaration    // class MyClass { void MyFunction(); }
Definition     // void MyClass::MyFunction() { ... }