(C++) 与命名空间链接会导致重复符号错误
在过去的几天里,我一直在尝试弄清楚如何链接我一直在从事的 CLI 游戏项目的文件。该项目有两部分,客户端代码和服务器代码。
客户需要我制作的两个库。第一个是通用游戏板。它分为 GameEngine.h 和 GameEngine.cpp。头文件看起来像这样
namespace gfdGaming {
// struct sqr_size {
// Index x;
// Index y;
// };
typedef struct { Index x, y; } sqr_size;
const sqr_size sPos = {1, 1};
sqr_size sqr(Index x, Index y);
sqr_size ePos;
class board
{
// Prototypes / declarations for the class
}
}
CPP 文件只是提供所有内容
#include "GameEngine.h"
type gfdGaming::board::functions
客户端还有游戏特定的代码(在本例中为 TicTacToe),分为声明和定义(TTT.h、Client.cpp)。 TTT.h 基本上是
#include "GameEngine.h"
#define TTTtar "localhost"
#define TTTport 2886
using namespace gfdGaming;
void* turnHandler(void*);
namespace nsTicTacToe
{
GFDCON gfd;
const char X = 'X';
const char O = 'O';
string MPhostname, mySID;
board TTTboard;
bool PlayerIsX = true, isMyTurn;
char Player = X, Player2 = O;
int recon(string* datHolder = NULL, bool force = false);
void initMP(bool create = false, string hn = TTTtar);
void init();
bool isTie();
int turnPlayer(Index loc, char lSym = Player);
bool checkWin(char sym = Player);
int mainloop();
int mainloopMP();
}; // NS
我决定将其放在命名空间中以将其分组而不是类,因为有些部分在 OOP 中不能很好地工作,并且以后实现起来要容易得多。
我过去在链接客户端时遇到了麻烦,但这个设置似乎有效。
我的服务器也分为两个文件,Server.h 和 Server.cpp。
Server.h 准确包含:
#include "../TicTacToe/TTT.h" // Server needs a full copy of TicTacToe code
class TTTserv;
struct TTTachievement_requirement {
Index id;
Index loc;
bool inUse;
};
struct TTTachievement_t {
Index id;
bool achieved;
bool AND, inSameGame;
bool inUse;
bool (*lHandler)(TTTserv*);
char mustBeSym;
int mustBePlayer;
string name, description;
TTTachievement_requirement steps[safearray(8*8)];
};
class achievement_core_t : public GfdOogleTech {
public: // May be shifted to private
TTTachievement_t list[safearray(8*8)];
public:
achievement_core_t();
int insert(string name, string d, bool samegame, bool lAnd, int lSteps[8*8], int mbP=0, char mbS=0);
};
struct TTTplayer_t {
Index id;
bool inUse;
string ip, sessionID;
char sym;
int desc;
TTTachievement_t Ding[8*8];
};
struct TTTgame_t {
TTTplayer_t Player[safearray(2)];
TTTplayer_t Spectator;
achievement_core_t achievement_core;
Index cTurn, players;
port_t roomLoc;
bool inGame, Xused, Oused, newEvent;
};
class TTTserv : public gSserver {
TTTgame_t Game;
TTTplayer_t *cPlayer;
port_t conPort;
public:
achievement_core_t *achiev;
thread threads[8];
int parseit(string tDat, string tsIP);
Index conCount;
int parseit(string tDat, int tlUser, TTTplayer_t** retval);
private:
int parseProto(string dat, string sIP);
int parseProto(string dat, int lUser);
int cycleTurn();
void setup(port_t lPort = 0, bool complete = false);
public:
int newEvent;
TTTserv(port_t tlPort = TTTport, bool tcomplete = true);
TTTplayer_t* userDC(Index id, Index force = false);
int sendToPlayers(string dat, bool asMSG = false);
int mainLoop(volatile bool *play);
};
// Other
void* userHandler(void*);
void* handleUser(void*);
在 CPP 文件中,我包含 Server.h 并提供 main() 以及先前声明的所有函数的内容。
现在解决手头的问题 我在链接服务器时遇到问题。更具体地说,我在 nsTicTacToe 中(也可能在 gfdGaming 中)的每个变量都收到重复符号错误。由于我需要 TicTacToe 函数,因此我在构建服务器时链接了 Client.cpp (不带 main() )
ld: duplicate symbol nsTicTacToe::PlayerIsX in Client.o and Server.o
collect2: ld returned 1 exit status
Command /Developer/usr/bin/g++-4.2 failed with exit code 1
It stops once a problem is encountered, but if PlayerIsX is removed / changed temporarily than another variable causes an error
本质上,我正在寻找有关如何更好地组织我的代码以希望修复这些错误的任何建议。
免责声明: - 如果我提供的信息太多或太少,我提前道歉,因为这是我第一次发帖
- 我尝试使用 static 和 extern 来解决这些问题,但显然这些不是我需要的
感谢任何接受的人是时候阅读所有这些并做出回应 =)
For the past few days, I have been trying to figure out how to link the files for a CLI gaming project I have been working on. There are two halves of the project, the Client and the Server code.
The client needs two libraries I've made. The first is a general purpose game board. This is split between GameEngine.h and GameEngine.cpp. The header file looks something like this
namespace gfdGaming {
// struct sqr_size {
// Index x;
// Index y;
// };
typedef struct { Index x, y; } sqr_size;
const sqr_size sPos = {1, 1};
sqr_size sqr(Index x, Index y);
sqr_size ePos;
class board
{
// Prototypes / declarations for the class
}
}
And the CPP file is just giving everything content
#include "GameEngine.h"
type gfdGaming::board::functions
The client also has game-specific code (in this case, TicTacToe) split into declarations and definitions (TTT.h, Client.cpp). TTT.h is basically
#include "GameEngine.h"
#define TTTtar "localhost"
#define TTTport 2886
using namespace gfdGaming;
void* turnHandler(void*);
namespace nsTicTacToe
{
GFDCON gfd;
const char X = 'X';
const char O = 'O';
string MPhostname, mySID;
board TTTboard;
bool PlayerIsX = true, isMyTurn;
char Player = X, Player2 = O;
int recon(string* datHolder = NULL, bool force = false);
void initMP(bool create = false, string hn = TTTtar);
void init();
bool isTie();
int turnPlayer(Index loc, char lSym = Player);
bool checkWin(char sym = Player);
int mainloop();
int mainloopMP();
}; // NS
I made the decision to put this in a namespace to group it instead of a class because there are some parts that would not work well in OOP, and it's much easier to implement later on.
I have had trouble linking the client in the past, but this setup seems to work.
My server is also split into two files, Server.h and Server.cpp.
Server.h contains exactly:
#include "../TicTacToe/TTT.h" // Server needs a full copy of TicTacToe code
class TTTserv;
struct TTTachievement_requirement {
Index id;
Index loc;
bool inUse;
};
struct TTTachievement_t {
Index id;
bool achieved;
bool AND, inSameGame;
bool inUse;
bool (*lHandler)(TTTserv*);
char mustBeSym;
int mustBePlayer;
string name, description;
TTTachievement_requirement steps[safearray(8*8)];
};
class achievement_core_t : public GfdOogleTech {
public: // May be shifted to private
TTTachievement_t list[safearray(8*8)];
public:
achievement_core_t();
int insert(string name, string d, bool samegame, bool lAnd, int lSteps[8*8], int mbP=0, char mbS=0);
};
struct TTTplayer_t {
Index id;
bool inUse;
string ip, sessionID;
char sym;
int desc;
TTTachievement_t Ding[8*8];
};
struct TTTgame_t {
TTTplayer_t Player[safearray(2)];
TTTplayer_t Spectator;
achievement_core_t achievement_core;
Index cTurn, players;
port_t roomLoc;
bool inGame, Xused, Oused, newEvent;
};
class TTTserv : public gSserver {
TTTgame_t Game;
TTTplayer_t *cPlayer;
port_t conPort;
public:
achievement_core_t *achiev;
thread threads[8];
int parseit(string tDat, string tsIP);
Index conCount;
int parseit(string tDat, int tlUser, TTTplayer_t** retval);
private:
int parseProto(string dat, string sIP);
int parseProto(string dat, int lUser);
int cycleTurn();
void setup(port_t lPort = 0, bool complete = false);
public:
int newEvent;
TTTserv(port_t tlPort = TTTport, bool tcomplete = true);
TTTplayer_t* userDC(Index id, Index force = false);
int sendToPlayers(string dat, bool asMSG = false);
int mainLoop(volatile bool *play);
};
// Other
void* userHandler(void*);
void* handleUser(void*);
And in the CPP file I include Server.h and provide main() and the contents of all functions previously declared.
Now to the problem at hand
I am having issues when linking my server. More specifically, I get a duplicate symbol error for every variable in nsTicTacToe (and possibly in gfdGaming as well). Since I need the TicTacToe functions, I link Client.cpp ( without main() ) when building the server
ld: duplicate symbol nsTicTacToe::PlayerIsX in Client.o and Server.o
collect2: ld returned 1 exit status
Command /Developer/usr/bin/g++-4.2 failed with exit code 1
It stops once a problem is encountered, but if PlayerIsX is removed / changed temporarily than another variable causes an error
Essentially, I am looking for any advice on how to better organize my code to hopefully fix these errors.
Disclaimers:
-I apologize in advance if I provided too much or too little information, as it is my first time posting
-I have tried using static and extern to fix these problems, but apparently those are not what I need
Thank you to anyone who takes the time to read all of this and respond =)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您会收到有关重复定义的错误,因为这就是您所拥有的:每次 .cpp 文件包含 TTT.h 时,都会定义一个全局
bool PlayerIsX
(在 nsTicTacToe 命名空间中,但仍然是全局的)。在本例中,Server.cpp 和 Client.cpp 包含它。解决此问题的一种方法是使用 extern 将定义更改为声明,然后在相应的 .cpp 文件(例如 TTT.cpp)中执行实际定义。
在 TTT.h 中:
在 TTT.cpp 中:
等等其他定义。
顺便说一下,请记住有适当的保护#ifdef:
You get error about duplicate definitions because that's what you have: each time a .cpp file includes TTT.h, a global
bool PlayerIsX
is defined (in the nsTicTacToe namespace, but still global). In this case, it's Server.cpp and Client.cpp that are including it.One way to solve this could be to change the definitions into declarations by using
extern
, then doing the actual definition in a corresponding .cpp file (TTT.cpp, for instance).In TTT.h:
In TTT.cpp:
and so on for the other definitions.
By the way, remember to have proper guard
#ifdef
s:实际上,
extern
就是您所需要的。您可能只是没有意识到或记得您还必须在 cpp 文件中定义此类变量。header:
source:
通过将所有全局变量放入标头中,您将在包含它们的任何地方复制它们,这正是编译器所抱怨的。
Actually,
extern
IS what you need. You're probably just not realizing or remembering that you'll also have to define such variables in a cpp file.header:
source:
By putting all of your globals in the header you're making copies of them everywhere you include them, which is exactly what your compiler is bitching about.
您本质上是在使用全局变量,这在 C++ 中是强烈不推荐的,但有时在 C 中是必需的。
您可以使其与 extern 一起使用,但“更好”的答案是将全局变量包装在某种状态对象中。
在 Main 中创建状态对象并将其传递给需要了解游戏系统状态的每个函数。
从长远来看,这将带来更好的代码组织。
You are essentially using globals, which is strongly not recommended in C++, but is sometimes necessary in C.
You could get it working with extern, but the "better" answer would be to wrap your globals in a state object of some sort.
Create your state object in Main and pass it to each function that needs to know the state of the game system.
This will lead to much better code organization in the long run.
您可以将命名空间 nsTicTacToe 部分放入它自己的 .cpp 文件中,单独编译并链接它。
您可能还需要一个仅声明变量的外部的头文件,并将其包含在客户端和服务器 .cpp 文件中。
you could put the namespace nsTicTacToe part into it's own .cpp file, compile it separately and link it in.
You might also need a header file which just declares externs for the variables, and include that in you client and server .cpp files.