40

たまたま.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)はclient.objですでに定義されています

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

ご覧のとおり、私はクラスを二重に定義/含めているわけではなく、main.hに1回だけ含まれています。では、ここで何が起こっているのでしょうか。私はこの答え を読みましたが、それは二重の包含を期待しているので、それは助けにはなりませんでした。これは単に容赦なく斬首することを意味するので、重複に投票する前にこの事実を無視してください。

4

3 に答える 3

62

これはコンパイラエラーではありません。エラーはリンカから発生しています。コンパイル後、リンカは各変換ユニット(.cppファイル)のコンパイルの結果であるオブジェクトファイルをマージします。

リンカは、同じシンボルが異なる変換単位で複数回定義されていることを検出し、それについて不平を言います(これは単一定義規則の違反です)。

その理由は間違いなくがmain.cpp含まれていることclient.cppであり、これらのファイルは両方ともコンパイラによって個別に処理され、2つの別々のオブジェクトファイルが生成されます。したがって、翻訳単位で定義されているすべての記号は、client.cpp翻訳単位でも定義されmain.cppます。#include .cppこれが、通常ファイルを作成しない理由の1つです。

クラスの定義を、そのクラスのメンバー関数の定義も含まないclient.hpp別のファイルに入れます。次に、そのファイルを含めます(つまり)。最後に、クラスのメンバー関数の定義を残します。client.cppmain.cpp#includeclient.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"
于 2013-03-14T22:24:30.120 に答える
13

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

#include "client.cpp"

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

これ が重要です#ifndef SOCKET_CLIENT_CLASS。ただし、持っている各ファイル#include "client.cpp" は個別にビルドされているためSOCKET_CLIENT_CLASS、まだ定義されていません。したがって、その内容は#ifdefではなく、含まれます。

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

于 2013-03-14T22:26:07.160 に答える
5

2つの塗りつぶし(.h .cpp)で実行することをお勧めしますがinline、関数の前に追加するのが面倒な場合は、次のようになります。

inline void functionX() 
{ }

インライン関数の詳細:

インライン関数は、プログラムの実行時間を増やすためのC++拡張機能です。関数は、コンパイラーにインライン化するように指示することができます。これにより、コンパイラーは、呼び出されている場所でそれらの関数定義を置き換えることができます。コンパイラは、実行時に関数定義を参照する代わりに、コンパイル時にインライン関数の定義を置き換えます。注-これは、関数をインライン化するためのコンパイラへの単なる提案です。関数が大きい場合(実行可能命令など)、コンパイラは「インライン」要求を無視して、関数を通常の関数として扱うことができます。

詳細はこちら

于 2020-06-26T19:38:38.460 に答える