2013-09-22 3 views
2

Я относительно новичок в C++ и сталкиваюсь с проблемой циклической зависимости. Может кто-то, пожалуйста, помогите мне решить это?Циркулярная зависимость в классах 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); 
}; 

Приведенный выше код дает следующие ошибки:

  • 'Vertex' не называет тип
  • 'Vertex' не был объявлен
  • ожидаемый ')' до 'v'

Как исправить эту проблему?

+3

Прочитайте это: http://stackoverflow.com/questions/553682/when-to-use-forward -declaration – BartoszKP

+0

Я не уверен, что понимаю, что такое '' Vertex''. Вершины, которые я обычно думаю, не имеют имен и/или ребер. – Shoe

ответ

5

Все, что вам нужно переслать, объявить 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); 
}; 
+0

У меня есть два разных файла заголовка для классов Vertex и Edge. – AnilJ

+0

Все в порядке. Строка с 'class Edge;' принадлежит 'Vertex.h'. Затем 'Edge.h' должен включать' Vertex.h'. –

2

Если вы думаете об этом, инстанцировании один Vertex или Edge объекта будет инстанцируют бесконечное количество больше Vertex и Edge объектов, потому что каждый из них содержит экземпляры друг друга.

Чтобы исправить это, вам необходимо переслать объявление класса, который зависит от того, который вы используете в первую очередь. Классы прямого декларирования позволяют использовать указатели и ссылки на них без фактического с использованием класса, только указывающего на него.

Этот фрагмент должен быть скомпилирован, но для этого потребуется некоторое дополнительное управление памятью.

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 предлагает вам ознакомиться с forward declarations, вам, возможно, потребуется узнать больше о указателях и ссылках.


Поскольку у вас все еще есть проблемы, я уточню свой ответ с более подробной информацией. Я прочитал, что вы фактически разделили свои классы на два файла заголовка, я полагаю, что они Vertex.h и Edge.h. Они должны выглядеть примерно так:

Vertex.ч

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

edge.h

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

Вам нужно будет включать в себя полное определение Edge, когда вы хотите использовать его для доступа к своим членам или создания экземпляра. В основном вам нужно поместить реализации каждой функции после того, как будут определены все классы и структуры. Самый простой способ сделать это - поместить функции в свой файл .cpp. Похоже, вы хотите создать объект Edge из класса Vertex, поэтому вам нужно сделать это в файле Vertex.cpp.

Vertex.cpp

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

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

Поскольку первое, что было сделано в этом .cpp файле, включая заголовочные файлы Vertex и Edge, которые имеют свои соответствующие определения классов, вы можете полностью использовать 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() { ... } 
+0

После некоторых изменений я вижу новую проблему, которая не позволяет мне создать объект Edge в классе Vertex, где Edge объявлен вперед. Каким образом я смогу создать объект класса Edge? Это дает мне ошибку - «недопустимое использование неполного типа» struct Edge »« – AnilJ

+0

Я обновил свое объяснение, чтобы помочь с вашей новой проблемой. – FakeTruth

Смежные вопросы