arquivos de cabeçalho C ++ - Confuso!
-
23-08-2019 - |
Pergunta
game.h needs:
- packet.h
- socket.h
server.h needs:
- socket.h
socket.h needs:
- game.h
O problema surge quando eu tento incluir socket.h em game.h, porque socket.h tem game.h já incluído. Como faço para resolver este tipo de problemas?
Solução
A maneira usual, use #ifdef e #define em seus arquivos de cabeçalho
game.h dentro:
#ifndef GAME_H
#define GAME_H
.. rest of your header file here
#endif
Desta forma, o conteúdo será lido várias vezes, mas apenas definido uma vez.
Editar :. Sublinhados removidos em início e fim do identificador por comentários
Outras dicas
A chave é a declaração para a frente. Levar o material a partir de game.h
que é necessário em socket.h
(ou vice-versa) e para a frente-declarar que em ainda outro cabeçalho, por exemplo game_forwards.h
. Como exemplo, considere o seguinte:
// 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
Claramente, para que isso funcione, é importante interface e implementação separada.
Além das técnicas (definição para a frente e de leitura uma vez cabeçalhos), você precisa trabalhar fora porque seu cabeçalho tomada requer qualquer coisa, desde o cabeçalho jogo, e empacotar seu sistema em módulos com uma única ordem de dependência. Não deve haver qualquer razão uma classe tomada precisa saber sobre o jogo que está a ser utilizado.
Para completar, uma outra alternativa é:
#pragma once
no topo do arquivo.
Isto tem a vantagem de que o arquivo não é aberto repetidamente, poupando tempo de compilação.
Ele tem a desvantagem de não ser padrão, de modo que nem todos os compiladores apoiá-lo. Funciona de forma confiável no Visual C ++.
Não há nenhuma maneira elegante em torno dele que eu posso pensar - sua melhor aposta é de transmitir-definir as funções que serão realmente utilizados. Então, se game.h só usa a função connect () de socket.h, adicionar esta linha ao game.h:
void connect();
E remover a importação socket.h. Claro, se a assinatura do connect () muda você precisa se lembrar de atualizar a definição para a frente também, então esta solução está longe de ser ideal. Se você possivelmente pode, modificar o projeto para evitar as dependências circulares.
Se game.h só precisa saber sobre uma classe em socket.h, frente defini-lo como este:
class Socket;
Existem algumas ressalvas quando se trata de funções embutidas e objetos membro, consulte A C ++ FAQ Lite .
@lassevk, não deve que ser "o arquivo de cabeçalho será aberta várias vezes, mas o pré-processador só irá ler o conteúdo do arquivo entre o #ifndef e #endif uma vez, durante a primeira leitura. Depois, em seguida, o pré-processador irá ignorar bewteen as macros PP porque _GAME_H foi definido ".