Заголовочные файлы C ++ - Confused! - PullRequest
5 голосов
/ 21 декабря 2008
game.h needs:
- packet.h
- socket.h

server.h needs:
- socket.h

socket.h needs:
- game.h

Проблема возникает, когда я пытаюсь включить socket.h в game.h, потому что в socket.h уже включен game.h. Как мне решить подобные проблемы?

Ответы [ 6 ]

17 голосов
/ 21 декабря 2008

Как обычно, используйте #ifdef и #define в заголовочных файлах

внутри game.h:

#ifndef GAME_H
#define GAME_H

.. rest of your header file here

#endif

Таким образом, содержимое будет прочитано несколько раз, но определено только один раз.

Редактировать : убраны подчеркивания в начале и конце идентификатора для комментариев.

9 голосов
/ 21 декабря 2008

Ключ - предварительная декларация. Возьмите материал из game.h, который требуется в socket.h (или наоборот), и объявите его в еще одном заголовке, например, game_forwards.h. В качестве примера рассмотрим следующее:

// game_fwd.h

#ifndef GAME_FWD_H
#define GAME_FWD_H

class game;

#endif // ndef GAME_FWD_H

// game.h

#ifndef GAME_H
#define GAME_H

#include "socket.h"

class game {
    socket* m_sck;
};

#endif // ndef GAME_H

// socket.h

#ifndef SOCKET_H
#define SOCKET_H

#include "game_fwd.h"

class socket {
    game* m_game;
};

#endif // ndef SOCKET_H

Очевидно, чтобы это работало, важно разделить интерфейс и реализацию.

8 голосов
/ 21 декабря 2008

В дополнение к методам (прямое определение и заголовки с однократным чтением) вам необходимо выяснить, почему заголовок сокета требует чего-либо из заголовка игры, и упаковать вашу систему в модули с единым порядком зависимостей. Не должно быть никаких причин, чтобы класс сокета должен был знать о том, для какой игры он используется.

3 голосов
/ 21 декабря 2008

Для полноты, другая альтернатива:

#pragma once 

вверху файла.

Преимущество заключается в том, что файл не открывается повторно, что экономит время компиляции.

Недостатком является то, что он не является стандартным, поэтому не все компиляторы поддерживают его. Надежно работает в Visual C ++.

1 голос
/ 21 декабря 2008

Я не могу придумать элегантного способа обойти это - лучший выбор - определить функции, которые будут фактически использоваться. Итак, если game.h использует только функцию connect () из socket.h, добавьте эту строку в game.h:

void connect();

И удалите файл socket.h import. Конечно, если сигнатура connect () изменится, вам также нужно помнить об обновлении прямого определения, так что это решение далеко от идеала. Если возможно, измените дизайн, чтобы избежать циклических зависимостей.

Если game.h просто нужно знать о классе в socket.h, определите его следующим образом:

class Socket;

Существуют некоторые оговорки, когда речь идет о встроенных функциях и объектах-членах, см. C ++ FAQ Lite .

0 голосов
/ 21 декабря 2008

@ lassevk, если это не так, «файл заголовка будет открыт несколько раз, но препроцессор будет только один раз прочитать содержимое файла между #ifndef и #endif, во время первого чтения. будет игнорировать макросы PP, потому что _GAME_H был определен. "

...