Невозможно включить структуру в другой файл

Я делаю проект с несколькими файлами на С ++. У меня есть такой код:

lista.h

struct elem
{
    account info;
    elem* next;
};

typedef elem* lista;

Ошибка отображается здесь, где объявлено "lista * a".

login.h:

struct account
{
    string user = "";
    int hash_pass = 0;
};

struct list
{
   lista* a;
   int size;
};

login.cc:

#include "login.h"
#include "lista.h"
....

lista.cc

#include "login.h"
#include "lista.h"
....

В lista.cc и login.cc я включил login.h и lista.h, но в login.h не распознает lista как имя типа.

Вы тоже можете показать файлы .cc?

Yiğit Aras Tunalı 20.08.2018 10:51

@ YiğitArasTunalı я опубликовал часть включения

Interseba5 20.08.2018 10:54

Пожалуйста, покажите минимальный воспроизводимый пример и покажите все сообщения об ошибках, отображаемые при компиляции.

Jabberwocky 20.08.2018 10:55

Вам также не хватает защиты заголовка.

AmeyaVS 20.08.2018 10:57

@AmeyaVS охранник?

Interseba5 20.08.2018 11:00
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
201
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Если вы хотите использовать что-то, объявленное в A.h внутри B.h, вам нужно включить A.h в B.h. Следовательно, необходимо включить lista.h в login.h.

OP также должен будет включить охранников в свои файлы заголовков.

Martin Bonner supports Monica 20.08.2018 11:00

... и удалите теперь избыточный #include lista.h из login.cc

acraig5075 20.08.2018 11:02

@ acraig5075 Только если login.cc не использует ничего из самого lista.h. Если это так, вам следует сохранить включение, потому что кто знает, что произойдет с login.h в будущем - в конечном итоге он может больше не понадобиться / включать lista.h.

Max Langhof 20.08.2018 11:05

Включите lista.h в login.h, так как ваш заголовок входа в систему требует доступа к lista :)

Ваша проблема сводится к следующему:

struct elem
{
  account info;   // <<< account is not known here
  elem* next;     // elem is not known here
};

typedef elem* lista;   

struct account
{
  std::string user = "";
  int hash_pass = 0;
};

struct list
{
  lista* a;
  int size;
};    

typedef elem* lista;

Если вы исправите порядок объявлений, он компилируется нормально:

struct account
{
  std::string user = "";
  int hash_pass = 0;
};

struct elem
{
  account info;
  elem* next;
};

typedef elem* lista;

struct list
{
  lista* a;
  int size;
};
Ответ принят как подходящий

Круговая зависимость! Предполагая, что тип string четко определен где-то еще в файлах заголовков (может быть, std::string?), Это потому, что вы включили файлы в неправильном порядке.

#include "login.h"
#include "lista.h" 
....

Это в основном эквивалентно:

struct account
{
    string user = "";
    int hash_pass = 0;
};

struct list
{
   lista* a;
   int size;
};

struct elem
{
    account info;
    elem* next;
};

typedef elem* lista;
....

Как видите, lista появляется даже раньше, чем typedef, поэтому вы получаете сообщение об ошибке.

Очевидно, вам не нужно заботиться о том, в каком порядке вы включаете файлы заголовков, поэтому правильным решением здесь было бы включить lista.h в login.h с надлежащими защитами заголовков. Но в данном случае этого недостаточно: здесь существует круговая зависимость, поскольку lista.h требует struct account от login.h, а login.h требует lista от lista.h. Поэтому мы также добавляем форвардное объявление. См. эта ссылка для получения дополнительной информации. Тогда ваш окончательный код будет:

lista.h:

#ifndef LISTA_H_
#define LISTA_H_
struct account; // forward declaration

struct elem
{
    account* info; // notice that `account` now has to be a pointer
    elem* next;
};

typedef elem* lista;
#endif

login.h:

#ifndef LOGIN_H_
#define LOGIN_H_
#include "lista.h"

struct account
{
    string user = "";
    int hash_pass = 0;
};

struct list
{
   lista* a;
   int size;
};
#endif

Другие вопросы по теме