C++ C++;头文件-混乱!

C++ C++;头文件-混乱!,c++,header-files,C++,Header Files,当我尝试将socket.h包含到game.h中时,问题就出现了,因为socket.h已经包含game.h了。如何解决此类问题?通常,在头文件中使用#ifdef和#define 内线游戏。h: game.h needs: - packet.h - socket.h server.h needs: - socket.h socket.h needs: - game.h 这样,内容将被读取多次,但只定义一次 编辑:删除每个注释标识符开头和结尾的下划线。关键是转发声明。从game.h中取出sock

当我尝试将socket.h包含到game.h中时,问题就出现了,因为socket.h已经包含game.h了。如何解决此类问题?

通常,在头文件中使用#ifdef和#define

内线游戏。h:

game.h needs:
- packet.h
- socket.h

server.h needs:
- socket.h

socket.h needs:
- game.h
这样,内容将被读取多次,但只定义一次


编辑:删除每个注释标识符开头和结尾的下划线。

关键是转发声明。从
game.h
中取出
socket.h
中所需的内容(反之亦然),并在另一个标题中向前声明,例如
game\u forwards.h
。作为一个例子,考虑如下:

#ifndef GAME_H
#define GAME_H

.. rest of your header file here

#endif

显然,要使其工作,分离接口和实现是很重要的。

@lassevk,不是吗“头文件将被打开几次,但在第一次读取期间,预处理器将只读取一次#ifndef和#endif之间的文件内容。然后,预处理器将忽略PP宏中的BEW,因为已经定义了“GAME”。

我想不出什么好办法-最好是向前定义实际使用的函数。因此,如果GAME.H只使用socket.H中的connect()函数,请将这一行添加到GAME.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
并删除socket.h导入。当然,如果connect()的签名发生更改,您也需要记住更新转发定义,因此此解决方案远远不够理想。如果可能,请修改设计以避免循环依赖

如果game.h只需要知道socket.h中的一个类,请按如下方式定义它:

void connect();

关于内联函数和成员对象,还有一些注意事项,请参见。

除了这些技术(正向定义和一次读取标题),您需要了解为什么套接字标头需要游戏标头中的任何内容,并使用单个依赖项顺序将系统打包到模块中。套接字类不应该有任何理由需要知道它用于什么游戏。

为了完整性,另一种选择是:

class Socket;
在文件的顶部

这样做的优点是文件不会重复打开,从而节省了编译时间


它有不规范的缺点,所以不是所有编译器都支持它。在VisualC++中工作可靠。

这是属于问题的答案。真的,这可能是一个注释,但是给出了“绿色”。“问题的本质是,这可能会对提问者有所帮助。好吧,这取决于你的意思。当然,每次包含文件时,预处理器都会读取文件的内容,但是是的,它会忽略它,但它不能不读取就忽略内容,因为它需要找到#endif:)lassevk:因为这是公认的答案,也可以做正确的事情:C++不喜欢标识符开头的下划线(即使它是合法的,用于库)。@康拉德-我不认为这适用于预处理器宏。在我的Mac上,标准C++头文件只填充了这些定义。文件堆栈*这是一个标准的C++库标头。*/y*IFNDEF,GLYBCXXXFACTHOL**定义了MyGLBCXXXStUST1,下划线标识符被保留给标准库,这就是为什么允许它们使用它们的原因。也可以考虑使用其他答案中推荐的前向声明。如果可行,它不仅可以解决问题,还可以加快编译时间。当OP的问题与编译时间无关时,您建议进行编译器特定的优化,以包括保护。我从未建议OP的问题与编译时间有关。我只是想指出另一种处理include文件的可能方法,因为OP对这个问题来说似乎是相当新的。我几乎不认为这是一个反对票,但每个人都有自己的意见。:)令人惊叹的。太多的人试图解决问题,却没有意识到问题的存在。这是一个糟糕的命名。我的游戏类解析传入的数据包,套接字调用解析函数。。。有时,我的游戏类还需要发送数据包,它需要访问套接字class@Daniel当前位置无论名称如何,您仍然有一个扭曲的组织。正如Pete Kirkham所建议的那样,重新组织,这样你就可以拥有一个干净的、非乱伦的依赖集。
#pragma once