5

過去数日間、私は自分が取り組んでいるCLIゲームプロジェクトのファイルをリンクする方法を見つけようとしてきました。プロジェクトには、クライアントコードとサーバーコードの2つの部分があります。

クライアントには、私が作成した2つのライブラリが必要です。1つ目は汎用ゲームボードです。これは、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

クライアントには、宣言と定義(TTT.h、Client.cpp)に分割されたゲーム固有のコード(この場合はTicTacToe)もあります。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の2つのファイルに分割されています。

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を使用しようとしましたが、どうやらそれらは私が必要とするものではありません

このすべてを読んで応答するために時間を割いてくださった方に感謝します=)

4

4 に答える 4

7

重複した定義についてエラーが発生するのは、それが原因です。.cppファイルにTTT.hが含まれるたびに、グローバルbool PlayerIsXが定義されます(nsTicTacToe名前空間で定義されますが、グローバルです)。この場合、それを含むのはServer.cppとClient.cppです。

これを解決する1つの方法は、を使用して定義を宣言に変更externし、対応する.cppファイル(たとえば、TTT.cpp)で実際の定義を実行することです。

TTT.hの場合:

namespace nsTicTacToe {
   ...
   extern bool PlayerIsX;
   ...
}

TTT.cppの場合:

#include "TTT.h"

bool nsTicTacToe::PlayerIsX;

他の定義についても同様です。

ちなみに、適切なガードを持っていることを忘れないでください#ifdef

#ifndef __TTT_H
#define __TTT_H
... header contents
#endif   // __TTT_H
于 2011-01-15T23:02:15.793 に答える
4

実際、externあなたが必要としているのはそれです。おそらく、cppファイルでそのような変数を定義する必要があることに気付いていないか覚えていないだけです。

ヘッダ:

extern int somevar;

ソース:

int somevar = ?;

すべてのグローバルをヘッダーに配置することで、それらを含めるすべての場所にそれらのコピーを作成します。これは、まさにコンパイラが苦労していることです。

于 2011-01-15T23:11:46.490 に答える
3

基本的にグローバルを使用しています。これはC++では強く推奨されていませんが、Cでは必要な場合があります。

externで動作させることもできますが、「より良い」答えは、グローバルをある種の状態オブジェクトでラップすることです。

struct State
{
  GFDCON gfd;
  const char X;
  const char O;
  string MPhostname, mySID;
  board TTTboard;
  bool PlayerIsX, isMyTurn;
  char Player, Player2;
};

Mainで状態オブジェクトを作成し、ゲームシステムの状態を知る必要がある各関数に渡します。

これにより、長期的にはコード編成が大幅に改善されます。

于 2011-01-15T23:04:25.883 に答える
1

名前空間nsTicTacToe部分を独自の.cppファイルに入れ、個別にコンパイルしてリンクすることもできます。また、変数のexternを宣言するだけのヘッダーファイルが必要な場合があり、それをクライアントおよびサーバーの.cppファイルに含めます。

于 2011-01-15T23:02:40.877 に答える