まず、必要なファイル以外のファイルで表示する必要のないヘッダーには何も入れないでください。次に、必要なものを以下に定義しましょう。
翻訳ユニット
変換ユニットは、コンパイルされている現在のコードであり、直接または間接的に、それに含まれるすべてのコードです。1つの変換ユニットが1つの.o/.objファイルに変換されます。
プログラム
これが、プロセスを形成するために実行できる1つのバイナリファイルにリンクされたすべての.o/.objファイルです。
異なる翻訳単位を持つことの主なポイントは何ですか?
- 依存関係を減らして、1つのクラスの1つのメソッドを変更した場合に、プログラムのすべてのコードを再コンパイルする必要はなく、影響を受ける変換ユニットのみを再コンパイルする必要があります。アン
- 他の翻訳ユニットがリンクしているときに表示されない翻訳ユニットのローカル名を使用することで、名前の衝突の可能性を減らします。
では、コードをさまざまな翻訳単位に分割するにはどうすればよいでしょうか。答えは「そうする」ということはありませんが、ケースバイケースで検討する必要があります。さまざまなクラスがあり、さまざまな翻訳単位に配置することができ、配置する必要があるため、多くの場合明らかです。
foo.hpp:
/* Only declaration of class foo we define below. Note that a declaration
* is not a definition. But a definition is always also a declaration */
class foo;
/* definition of a class foo. the same class definition can appear
in multiple translation units provided that each definition is the same
basicially, but only once per translation unit. This too is called the
"One Definition Rule" (ODR). */
class foo {
/* declaration of a member function doit */
void doit();
/* definition of an data-member age */
int age;
};
いくつかの無料の関数とオブジェクトを宣言します。
/* if you have translation unit non-local (with so-called extern linkage)
names, you declare them here, so other translation units can include
your file "foo.hpp" and use them. */
void getTheAnswer();
/* to avoid that the following is a definition of a object, you put "extern"
in front of it. */
extern int answerCheat;
foo.cpp:
/* include the header of it */
#include "foo.hpp"
/* definition of the member function doit */
void foo::doit() {
/* ... */
}
/* definition of a translation unit local name. preferred way in c++. */
namespace {
void help() {
/* ... */
}
}
void getTheAnswer() {
/* let's call our helper function */
help();
/* ... */
}
/* define answerCheat. non-const objects are translation unit nonlocal
by default */
int answerCheat = 42;
bar.hpp:
/* so, this is the same as above, just with other classes/files... */
class bar {
public:
bar(); /* constructor */
};
bar.cpp:
/* we need the foo.hpp file, which declares getTheAnswer() */
#include "foo.hpp"
#include "bar.hpp"
bar::bar() {
/* make use of getTheAnswer() */
getTheAnswer();
}
匿名の名前空間(上記のように)内の名前は、翻訳単位ローカルであるように見えるため、衝突しないことに注意してください。実際にはそうではなく、衝突しないように一意の名前を持っているだけです。翻訳ユニットのローカル名が本当に必要な場合(たとえば、Cコードが関数を呼び出すことができるようにcとの互換性があるため)、次のように実行できます。
static void help() {
/* .... */
}
ODRは、1つのプログラムにオブジェクトまたは非インライン関数の複数の定義を含めることはできないとも述べています(クラスはオブジェクトではなく型であるため、それらには適用されません)。したがって、非インライン関数をヘッダーに入れたり、「intfoo;」のようなオブジェクトを入れたりしないように注意する必要があります。ヘッダーで。これにより、リンカーがこれらのヘッダーを含む変換ユニットをリンクしようとしたときに、リンカーエラーが発生します。
私はあなたを少し助けることができると思います。長い答えでしたが、確かにどこかにエラーがあります。翻訳単位は厳密に別の方法(プリプロセッサの出力)で定義されていることを私は知っています。しかし、それを上記に含めることは大きな価値をもたらさないと私は思います、そしてそれは問題を混乱させるでしょう。本当のバグを見つけたら、遠慮なく私を叩いてください:)