web-dev-qa-db-ja.com

既に.objで定義されています-二重の包含はありません

私はたまたま.objエラーで既に定義されているものを取得しました。これは私のプロジェクトの構造です:

main.cpp

#include "main.h";

main.h

#include <iostream>
#include <string>
#include <sstream>
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
#include "client.cpp"

client.cpp

#ifndef SOCKET_CLIENT_CLASS
#define SOCKET_CLIENT_CLASS
#ifndef BOOST_ASIO_HPP
#include <boost/asio.hpp>
#endif
/*CLASS DEFINITION HERE*/
#endif

これはコンパイラが不満を言っていることです:

main.obj:エラーLNK2005: "public:bool __thiscall SocketClient :: read(int、char *)"(?read @ SocketClient @@ QAE_NHPAD @ Z)already defined client.obj内

ブーストではなく、クラスについて不平を言っていることに注意してください。興味深いことに、#include <boost/asio.hpp>client.cppから削除すると、エラーが発生しますmain.hにも含まれています

ご覧のように、クラスを二重に定義/インクルードしているわけではありません。インクルードexactly once inmain.h。ここで何が起こっているのでしょうか?
私は この回答 を読みましたが、二重の包含を期待するため、助けにはなりませんでした。これは単に容赦なく私を斬首することを意味するので、この事実を複製に投票する前に監視してください。

25
Tomáš Zato

これはcompilerエラーではありません:エラーはlinkerから発生しています。コンパイル後、リンカは各翻訳単位のコンパイルの結果のオブジェクトファイル(.cppファイル)をマージします。

リンカは、異なる翻訳単位で同じシンボルが複数回定義されていることを知り、それについて文句を言います(1つの定義ルールに違反しています)。

main.cppにはclient.cppが含まれており、これらのファイルは両方ともコンパイラーによって個別に処理され、twoが生成されるためです。オブジェクトファイル。したがって、client.cpp翻訳単位で定義されているすべてのシンボルは、main.cpp翻訳単位でも定義されます。これは、通常#include.cppファイルを使用しない理由の1つです。

クラスの定義を、そのクラスのメンバー関数の定義も含むnotを含む別のclient.hppファイルに入れます。次に、client.cppmain.cppにそのファイルを含めます(つまり、#include)。最後に、client.cppにクラスのメンバー関数の定義を残します。

client.h

#ifndef SOCKET_CLIENT_CLASS
#define SOCKET_CLIENT_CLASS
#ifndef BOOST_ASIO_HPP
#include <boost/asio.hpp>
#endif

class SocketClient // Or whatever the name is...
{

// ...

    bool read(int, char*); // Or whatever the name is...

//  ...
};

#endif

client.cpp

#include "Client.h"

// ...

bool SocketClient::read(int, char*)
{
    // Implementation  goes here...
}

// ... (add the definitions for all other member functions)

main.h

#include <iostream>
#include <string>
#include <sstream>
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
#include "client.h"
//              ^^ Notice this!

main.cpp

#include "main.h"
41
Andy Prowl

あなたはおそらくこれをしたくないでしょう:

#include "client.cpp"

* .cppファイルは、ビルドの一部としてコンパイラーによってコンパイルされます。他のファイルに含めることで、それを含むすべてのファイルで再度コンパイルされます(そして再び!)。

今ここにあります:#ifndef SOCKET_CLIENT_CLASSで保護していますが、#include "client.cpp"を持つ各ファイル独立してビルドされますなので、SOCKET_CLIENT_CLASSはまだ定義されていません。したがって、#ifdefで除外されたものではなく、その内容が含まれます。

(宣言ではなく)定義がまったく含まれている場合、これらの定義は含まれるすべてのファイルで繰り返されます。