简体   繁体   English

C ++头文件 - 困惑!

[英]C++ Header files - Confused!

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

server.h needs:
- socket.h

socket.h needs:
- game.h

The problem comes when I try to include socket.h into game.h, because socket.h has game.h included already. 当我尝试将socket.h包含到game.h中时会出现问题,因为socket.h已经包含了game.h。 How do I solve these kind of problems? 我该如何解决这些问题?

The usual way, use #ifdef and #define in your header files 通常的方法是在头文件中使用#ifdef和#define

inside game.h: 在game.h内:

#ifndef GAME_H
#define GAME_H

.. rest of your header file here

#endif

This way, the contents will be read multiple times, but only defined once. 这样,内容将被多次读取,但只定义一次。

Edit : Removed underscores at start and end of identifier per comments. 编辑 :删除每个注释的标识符开头和结尾的下划线。

The key is forward declaration. 关键是前瞻性声明。 Take the stuff from game.h that is required in socket.h (or vice-versa) and forward-declare it in yet another header, eg game_forwards.h . 从采取的东西game.h了在需要socket.h在又一个首部,例如(或反之亦然)和前向声明它game_forwards.h As an example, consider the following: 例如,请考虑以下事项:

// 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

Clearly, for this to work, it's important to separate interface and implementation. 显然,为了实现这一点,将接口和实现分开是很重要的。

In addition to the techniques (forward definition and read-once headers), you need to work out why your socket header requires anything from the game header, and package your system into modules with a single dependency order. 除了技术(前向定义和一次读取头)之外,您还需要弄清楚为什么套接字头需要游戏头中的任何内容,并将系统打包成具有单个依赖顺序的模块。 There shouldn't be any reason a socket class needs to know about what game it is being used for. 套接字类不应该有任何理由知道它正在使用什么游戏。

For completeness, another alternative is: 为了完整起见,另一种选择是:

#pragma once 

at the top of the file. 在文件的顶部。

This has the advantage that the file is not opened repeatedly, saving compile time. 这样做的好处是文件不会重复打开,节省了编译时间。

It has the disadvantage of not being standard, so not all compilers support it. 它的缺点是不标准,因此并非所有编译器都支持它。 Works reliably in Visual C++. 在Visual C ++中可靠地工作。

There's no elegant way around it that I can think of - your best bet is to forward-define the functions that will actually be used. 我能想到的并没有优雅的方法 - 你最好的选择是前向定义实际使用的功能。 So, if game.h only uses the connect() function from socket.h, add this line to game.h: 因此,如果game.h仅使用socket.h中的connect()函数,则将此行添加到game.h:

void connect();

And remove the socket.h import. 并删除socket.h导入。 Of course if the signature of connect() changes you'll need to remember to update the forward definition too, so this solution is far from ideal. 当然,如果connect()的签名发生变化,你也需要记住更新前向定义,所以这个解决方案远非理想。 If you possibly can, modify the design to avoid the circular dependencies. 如果可能,请修改设计以避免循环依赖。

If game.h just needs to know about a class in socket.h, forward define it like this: 如果game.h只需要知道socket.h中的一个类,那么转发定义如下:

class Socket;

There are some caveats when it comes to inline functions and member objects, see The C++ FAQ Lite . 关于内联函数和成员对象有一些注意事项,请参阅The C ++ FAQ Lite

@lassevk,不应该是“头文件将被打开几次,但预处理器只会在第一次读取时读取#ifndef和#endif之间的文件内容。之后预处理器将忽略bewteen PP宏,因为已经定义了_GAME_H。“

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM