3

我对 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' 之前使用 ')'</li>

我该如何解决这个问题?

4

2 回答 2

7

您只需要在Edge类中使用它之前前向声明它Vertex

class Edge;

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

class Edge { ... };

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

当然,您可以将指针放在Vertexinside 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);
};
于 2013-09-22T00:07:25.083 回答
2

如果您考虑一下,实例化单个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. 他们应该看起来像这样

顶点.h

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

边缘.h

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

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

顶点.cpp

#include "Vertex.h"
#include "Edge.h"

Edge* Vertex::CreateEdge()
{
    return new Edge();
}

因为在这个.cpp文件中做的第一件事是包含VertexEdge头文件,它们有各自的类定义,你可以完全按照你的意愿使用Vertex和类。Edge

您需要按照一定的顺序组织声明和定义,如下所示

// 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() { ... }
于 2013-09-22T00:14:01.070 回答