2017-01-08 3 views
2

Я реализую структуру суффикса trie в C++, где я использую три класса: Trie, Node и Edge. Поскольку я использую классы, я разделял объявления функций/переменных в файлы заголовка (.hpp) и их реализации в соответствующих файлах .cpp. Теперь я не привык к этому (обычно я пишу все в одном .cpp-файле), но я думаю, что это выгодно как для удобочитаемости, так и для структуры.Циклические указатели в C++

Поэтому у меня есть следующие файлы:

  • Launcher.cpp, содержащий функцию Main().
  • Trie.hpp, содержащий декларации функций и переменных.
  • Trie.cpp, содержащий реализации функций, заявленных в Trie.hpp.
  • Node.hpp, содержащий декларации функций и переменных.
  • Node.cpp, содержащий реализации функций, объявленных в Node.hpp.
  • Edge.hpp, содержащий декларации функций и переменных.
  • Edge.cpp, содержащий реализации заявленных функций в Edge.hpp.

Теперь способ, которым я реализовал trie, состоит в том, что каждый Node имеет вектор типа Edge. Кроме того, я хочу, чтобы Edge имел указатель Node*, чтобы он указывал на другой узел (это то, что делают ребра). Теперь, хотя это похоже на циклическое определение, я помню, что он может быть достигнут (по крайней мере, я имел обыкновение делать это, когда мои программы были в одном .cpp-файле).

Но так как у нас теперь есть все эти отдельные файлы с большим количеством #include с на вершине, я должен #include 'Node.hpp' в Edge.hpp и #include 'Edge.hpp' в Node.hpp. Если я этого не сделаю, я получаю такие ошибки, как «Край не определен в этой области». Но если я все включает в себя, я получаю сообщение об ошибке типа бесконечномерного цикла:

enter image description here

Команды Я бег на

g++ -std=c++11 -Wall -o program Edge.cpp Node.cpp Trie.cpp Launcher.cpp 

Я надеюсь, что это то, что я должен бежать. Есть ли способ добиться того, чего я хочу без этих ошибок? Я уверен, что это сработает, если я поместил все в один файл.


EDIT: Я сделал следующее Edge.hpp, и кажется, что все работает нормально!

#ifndef EDGE_HPP 
#define EDGE_HPP 

#include <string> 

class Node;   //Forward definition 

using namespace std; 

class Edge{ 

    private: 
     string label; 
     Node* pointsTo; 

    public: 
     Edge(); 
     Edge(string, Node*); 
     string getLabel(); 
     Node* getPointsTo(); 

}; 

#endif 
+0

Возможно, это легко разрешить. Но вам нужно показать свой код. – selbie

+0

В редакторе 'Edge.hpp' должно быть достаточно декларации о переходе; как в, 'class Node;' Вам не нужно «#include» Node.hpp «' –

+0

@IgorTandetnik Это считается хорошей практикой? Это похоже на обман. –

ответ

2

Это простой случай форвардной декларации.

Теперь способ, которым я реализовал trie, состоит в том, что каждый Узел имеет вектор типа Edge.

Это будет переведено на что-то вроде этого, в файле заголовка узла:

class Edge; 

class Node { 

public: 
    std::vector<Edge> edges; 

    Node(); 
    ~Node(); 
}; 

Этого будет достаточно, чтобы объявить узел в его файле заголовка. Не нужно включать заголовочный файл Edge.

Теперь файл .cpp, определяющий конструктор и деструктор узла, должен содержать оба файла заголовка, чтобы оба класса были полностью объявлены.

Кроме того, я хочу, что край имеет указатель Node *, так что указывающего на другой узел (это то, что края делают).

И это просто переводит, в заголовочном файле Эджа:

class Node; 

class Edge { 

public: 
    Node *from_node; 
    Node *to_node; 

    // ... 
}; 

Опять же, не нужно включать Node «s файл заголовка.

Имея Node «заголовка файла s включают Edge» s заголовочный файл, а не вперед объявить класс, вероятно, будет тоже хорошо, только с Edge «s заголовка файла пересылая-объявить Node класс.

Единственное, что вам нужно иметь в виду, это то, что любой код, который должен использовать класс Edge, и работать с его Node, должен включать оба файла заголовка. Простое включение Edge будет недостаточным, так как этот код не получит декларацию каждого Node, что указывает край, если только заголовочный файл Node не включен.

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

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