web-dev-qa-db-ja.com

C ++での複数の定義エラーとこの問題を解決するための解決策

私はC++を初めて使用します。 C++での複数定義エラーに関して疑問があります。

プログラムに3つのファイルがあるとしましょう。 1つのヘッダーファイルと2つの.cppファイル。両方の.cppファイルにヘッダーファイルをインクルードしました。

  1. ヘッダーファイルでクラスを宣言し、まったく同じ方法で各.cppファイルでクラスを定義しました。では、このタイプの実装は複数の定義エラーを引き起こしますか?もしそうなら、それはクラス定義の2つのコピーがあり、コンパイラが2つの.oファイルのリンク中にどちらをとるかわからないためですか?

ヘッダーファイルでexternを使用し、ファイルの1つだけでクラスを定義することで、この問題を解決できますか?このメソッドを使用して問題を解決できる場合は、.cpp(クラス定義付き)をインクルードする必要がありますか? )他の.cppファイル(クラス定義なし)に?

  1. ヘッダーファイルでクラスを宣言して定義しました。この場合は上記(1で述べた)と同じですか?

  2. ヘッダーファイルでクラスを宣言し、各.cppファイルでクラスを定義しましたが、定義(関数本体)が異なります。では、このタイプの実装は複数の定義エラーを引き起こしますか?もしそうなら、関数本体が.cppファイルで異なるこの問題をどのように解決できますか?

5
starkk92

1)1つのcppファイルで「クラスを定義する」ことでこれを解決します。なぜ2つのファイルで定義したいのですか?

2)ヘッダーファイルで物事を定義するのではなく、宣言するだけです。このルールには例外があります。たとえば、インライン関数です。また、クラス自体を複数回定義することもできます(これは、クラスのメソッドとデータメンバーを宣言することを意味します(つまり、class XYZ { ... };)ただし、各定義は同一である必要があります。これを実現する最も簡単な方法は、ヘッダーファイルでクラスを1回定義することです。その場合、そのヘッダーファイルを複数の場所にインクルードした結果の各定義は必ず同一になります。

3)これはさらに愚かです。何かを2回定義することは1つのことですが、2回定義し、毎回異なる方法で定義することはさらに意味がありません。

問題は、物事を複数回定義する必要があると思う理由だと思います。そうしないでください。

また、「クラスを定義する」とはどういう意味かを明確にする必要があります。私はそれを、クラスのメソッドと静的メンバーを定義することを意味すると解釈しました。しかし、何か他のことを考えている場合は、混乱の原因となる可能性があります。いつものように、この種の用語の混乱を避けるための最良の方法は、いくつかのコードを投稿することです。

9
john

これらすべての質問に答えるには、宣言と定義の目的を確認するだけで済みます。

クラスの宣言は、単にクラスが存在し、どのコンテキストにあるかを示しています。クラスの場合、単純な前方宣言(_class Banana;_など)を使用すると、そのクラスへのポインターまたは参照を使用できますが、それだけです。

定義は、クラスが何であるかを正確に示しています。つまり、どのメンバーを持ち、どの基本クラスから派生するかです。クラスのメンバーにアクセスするとき、またはそのインスタンスのサイズを知る必要があるときはいつでも、これを利用できる必要があります。つまり、クラス定義をヘッダーファイルに配置して、クラスを使用するすべてのファイルのどこにでも含めることができるようにする必要があります。すべての定義が同一である限り、クラスは複数の変換単位で定義できると標準で規定されているため、これは問題ありません。

クラス定義は通常、次のようになります。

_class Banana
{
public: 
  Banana(){}

  void eat();

private:
  //....
};
_

ただし、このクラス定義は、非インラインメンバー関数ではなく、クラス自体の定義のみを意味することに注意してください。上記の例のvoid eat()など。これらは複数の変換単位で定義されていない可能性があるため、.cppファイルで定義する必要があります。

つまり、要するに:

  1. これは正しくありません。ヘッダーファイルで定義し、一致する.cppファイルで非インラインメンバー関数を定義するだけです。同じ関数を定義したり、複数のファイルに入力したりしないでください。
  2. .cppファイルでメンバー関数を個別に定義する限り、これは問題ありません。
  3. いいえ、1を参照してください。
4
Agentlien

いくつかの場所でクラスを定義することに問題はありません。定義をヘッダーに入れ、そのヘッダーを複数のソースファイルに#includeすると、まさにそれが起こります。ただし、クラスを定義するということは、そのメンバーを定義するのではなく、クラスに含まれる内容を書き出すことを意味することに注意してください。これはクラス定義です:

class C {
    void f();     // member function declaration
    void g() { }  // member function declaration with inline definition
    int i;        // member declaration
    static int j; // member declaration
};

ほとんどのものと同様に、単一のソースファイルで複数回定義することはできません。ただし、どこでも同じであるという条件で、必要な数のソースファイルに表示できます。

このクラス定義は、通常次のように、どこかで定義する必要がある2つのメンバーを宣言します。

void C::f() {
    std::cout << "In C::f\n";
}

int C::j = 3;

これらの定義は、プログラム全体で1回だけ表示できます。通常、それぞれはソースファイルで一度定義されます。

1
Pete Becker

1)プロジェクトに同じクラスの2つの定義を含めることはできません。そして、私はあなたがそれをどのように使うつもりなのか分かりません。動作が異なる1つのクラスのインスタンスを作成する場合は、次のような仮想関数を使用します。

class A {
public:
    virtual int foo() = 0;
}

class B : public A {
public:
    virtual int foo() { return 1; }
}

class C : public A {
public:
    virtual int foo() { return 2; }
}

2)ヘッダーファイル(Javaスタイル)でクラスを定義することもできますが、コンパイラーは他のファイルを作成するためにより多くのリソースを消費するため、このヘッダーを含めることは最善の方法ではありません。コンパイラを高速に動作させます-.cppファイルでクラスを定義します。

3)p.1参照

1
Vadim Prozorov