0

私の調査により、私が経験している問題は巡回冗長と呼ばれていると信じるに至りました。投稿されている解決策がわかりません。私は (かなり) C++ の初心者であり、Java のバックグラウンドが豊富です。

基本的に、互いに依存する 2 つのクラスがあります。クラス A にはクラス B オブジェクトのベクトルが含まれ、クラス B にはクラス A オブジェクトを入力として必要とするメソッドが含まれます。

問題を再現するコードを次に示します。

codelite g++ によると、エラーは school.h にあり、「このスコープで人が宣言されていません」です。また、「テンプレート引数 1 が無効です」および「テンプレート引数番号 2 が無効です」とも表示されます。次に、呼び出されるすべてのベクトル関数の非クラス型「int」について、他にいくつか。

main.cpp

#include <iostream>
#include <string>
#include "person.h"
#include "school.h"

int main() {
    person p;   
    school s;
    std::cout << p.name << std::endl;
    s.personVect.push_back(p);
    std::cout << s.personVect.size() << std::endl;
    std::cout << s.personVect.at(0).name << std::endl;
    p.test();
    return 0;
}

学校.h

#ifndef SCHOOL_H
#define SCHOOL_H
#include <vector>
#include "person.h"

class school
{
public:
    school();
    ~school();

    std::vector<person> personVect;


};

#endif // SCHOOL_H

学校.cpp

#include "school.h"    
school::school(){}    
school::~school(){}

person.h

#ifndef PERSON_H
#define PERSON_H
#include <string>
#include <vector>
#include "school.h"


class person {
public:

    std::string name;
    std::string phone;

    school doSomethingWithSchool();

    void test();

    person();
    ~person();

};

#endif // PERSON_H

人.cpp

#include "person.h"
#include <iostream>
using namespace std;

person::person()
{
    name = "marcus";
    phone = "0400000000";
}

person::~person()
{
}

void person::test() {
    cout << this->name;
}
school person::doSomethingWithSchool() {
    school s; 
}
4

4 に答える 4

2

この問題は、クラスの関係をより適切に設計することで解決できます。

APersonは で構成されSchoolていないため、School メンバーを持つ必要はありません。

ASchoolにはオブジェクトのコレクションがありPersonます。

人に学校で何かをしてもらいたい場合は、それを引数として渡します。このようにして、ポインター前方宣言を使用して問題を解決できます。

// Person.h
class School; // Forward declare school type.

// Person.cpp
Person::DoSomethingWithSchool(School* school);
于 2013-03-28T06:21:23.557 に答える
0

あなたの問題は、school.h に #include "person.h" ステートメントがあり、person.h に #include "school.h" ステートメントがあるという事実にあります。

ソリューション

schoolクラスでは、 の代わりにをvector<person>使用しますvector<person*>。ここに person.h を含める代わりに、ステートメントを追加しclass person;ます。あなたのクラスが何らかの形で最終的にオブジェクトschoolを変更すると仮定すると、ステートメント.person#include person.h#include school.h

エラーの説明

これは、コンパイル時に何が起こるかを順を追って説明したものです。

  1. main.cpp では、最初に person.h をインクルードします。プリプロセッサが行って person.h を見つけます。以前に含めたことがないので、PERSON_H はまだ定義されておらず、ifndef PERSON_H は現在 true です。それでは、ファイルの次の行に進みます。

  2. このファイルで最初に興味深いことは、PERSON_H が定義されていることです ( #fdefine PERSON_H)。次回#includeこのファイルを使用すると、プリプロセッサはファイル全体を #endif までスキップします。

  3. 2番目に興味深いことは、school.h がインクルードされることです。したがって、プリプロセッサは school.h を見つけます (まだ School クラスを処理していません!)。

  4. school.h で ( #define SCHOOL_H の後に) 最初に興味深いのは#include person.hであるため、プリプロセッサは person.h に戻ります(まだ Person クラスも処理していません!)。しかし、今回はPERSON_Hが定義済みなので、#ifndef PERSON_Hはfalseとなり、プリプロセッサはそのファイルの#endifまでスキップします((2)で述べたとおり)。そのため、Person クラスはまだ宣言されていません。

  5. 何もせずに学校に戻ります。この時点で、学校のクラスを宣言/定義しようとしています。プリプロセッサが person.h から school.h に戻って person.h に戻って school.h に戻り、ディレクティブのみを処理しているため、person クラスは宣言されていません#include

  6. コンパイラは、schoolクラス定義の処理を開始します。次に興味深いのは行std::vector<person> personVect;です。をインスタンス化しようとしましたvector<person>。しかしperson、(5) のため、ここは不明です (つまり、このスコープで宣言されていません)。これは、2 つのテンプレート引数エラーを説明しています: Avector<person>は実際には暗黙的に avector <person, allocator<person> >です。最初のテンプレート引数はpersonで、2 番目はallocator<person>です。は不明であるためperson、これらの引数は両方とも無効です。

解決策の説明

school.h に person.h が含まれ、person.h に school.h が含まれているという事実が、あなたが言及した循環依存の原因です。これを回避するには、ファイルで特定のクラスを使用することを宣言する別の方法が必要です。一般的なアプローチは、前方宣言class person;を使用することです。これは、ソリューションで言及したステートメントで、 の定義の前にありますschoolpersonこれは、 (クラスで使用されているようにschool) クラスを参照していることをコンパイラーに知らせる通常の宣言です。

ただし、 を構築するためにvector<person>、コンパイラはクラスがメモリ内でどのくらいのスペースpersonを占有するか (つまり、そのサイズ)も知る必要がありますclass person;。実際、コンパイラは、ヘッダー ファイル内の完全な定義が処理された後にのみ、クラスのサイズを認識します。しかし、それを行おうとすると、振り出しに戻ってしまいます (循環依存など)。私たちが知っているのは、へのポインタpersonのサイズです。これは、マシン固有であるためです (たとえば、32 ビット マシンでは、何かへのポインタのサイズは 32 ビットです)。したがって、実際vector<person*>に何であるかに関係なく、これは常に 32 ビット オブジェクトのベクトルであるため、インスタンス化できます。person

于 2013-03-28T07:07:44.483 に答える
0

person を#include "person.h"
ヘッダー ファイル ("school.h")に含める代わりに、 必要に応じて "person.h" をインクルードする C++ モジュール ("school.cpp")へのclass person;ポインターを記述して使用します。person

これには、機能面でもいくつかの利点があります。(コンパイル時間を短縮)

便利なリンク:

http://www.codeproject.com/Articles/547275/Whyplusisplusitplusbuildingplussopluslong-3f https://stackoverflow.com/a/553869/328260

于 2013-03-28T06:16:58.577 に答える
0

これを試して、

person.h

        #ifndef PERSON_H
        #define PERSON_H
        #include <string>
        #include <vector>

        class school;
        class person {
        public:

            std::string name;
            std::string phone;

            school doSomethingWithSchool();

            void test();

            person();
            ~person();

        };

        #endif // PERSON_H

学校.h

      #ifndef SCHOOL_H
      #define SCHOOL_H
      #include <vector>

      class person;
      class school
      {
      public:
          school();
          ~school();

          std::vector<person*> personVect;
      };

      #endif // SCHOOL_H

人.cpp

    #include "person.h"
    #include "school.h"
    #include <iostream>
    using namespace std;

    person::person()
    {
        name = "marcus";
        phone = "0400000000";
    }

    person::~person()
    {
    }

    void person::test() {
        cout << this->name;
    }
    school person::doSomethingWithSchool() {
        school s; 
        return s;
    }

そしてmain.cppで

    int main()
    {
        person *p = new person;   
        school s;
        std::cout << p->name << std::endl;
        s.personVect.push_back(p);
        std::cout << s.personVect.size() << std::endl;
        std::cout << s.personVect.at(0)->name << std::endl;
        p->test();
        delete p;
        return 0;
    }
于 2013-03-28T06:52:22.457 に答える