область действия — классы C ++, зависящие друг от друга, вызывая ошибку циклической зависимости

Мои поиски привели меня к мысли, что проблема, с которой я сталкиваюсь, называется циклической избыточностью. Я не понимаю ни одно из опубликованных решений. Я (довольно) новичок в C ++, из-за сильного Java-опыта.

В основном есть два класса, которые зависят друг от друга. Класс 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;
}

school.h

#ifndef SCHOOL_H
#define SCHOOL_H
#include <vector>
#include "person.h"
class school
{
public:
school();
~school();

std::vector<person> personVect;};

#endif // SCHOOL_H

school.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

person.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;
}

0

Решение

Эту проблему можно решить, разработав свои классовые отношения лучше.

Person не состоит из Schoolтак что не нужно иметь члена школы.

School имеет коллекцию Person объекты.

Если вы хотите, чтобы человек что-то делал со школой, передайте это в качестве аргумента. Таким образом, вы можете использовать указатели а также предварительные декларации решить вопрос.

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

// Person.cpp
Person::DoSomethingWithSchool(School* school);
3

Другие решения

Попробуй это,

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

school.h

      #ifndef SCHOOL_H
#define SCHOOL_H
#include <vector>

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

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

#endif // SCHOOL_H

person.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;
}
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 в вашем файле school.cpp, после утверждения #include school.h,

Это пошаговое описание того, что происходит при компиляции:

  1. В main.cpp вы сначала включаете person.h. Препроцессор идет и находит человека. Так как вы никогда не включали его раньше, PERSON_H еще не был определен, и ifndef PERSON_H в настоящее время имеет значение true. Итак, мы переходим к следующей строке в файле.

  2. первый Интересно, что в этом файле происходит то, что PERSON_H определяется (#fdefine PERSON_H). В следующий раз ты #include этот файл препроцессор собирается пропустить весь файл, прямо до #endif.

  3. второй Интересно, что School.h включается. Таким образом, препроцессор находит school.h (мы еще не обработали класс School!), Который до сих пор никогда не обрабатывался.

  4. Первая интересная вещь в school.h (после #define SCHOOL_H) — это #include person.h, так препроцессор возвращается to person.h (мы еще не обработали класс Person!). Но на этот раз PERSON_H уже определен, поэтому #ifndef PERSON_H имеет значение false, и препроцессор переходит к #endif в этом файле (как я упоминал в (2)). Так что класс Person до сих пор не объявлен.

  5. Мы возвращаемся в школу. Ничего не сделав. На данный момент, мы как раз собираемся объявить / определить школьный класс. Человек класса никогда не был объявлен потому что наш препроцессор перепрыгнул с person.h в school.h обратно на person.h обратно в school.h, только обработка #include директивы.

  6. Компилятор начинает проходить через school определение класса. Следующая интересная вещь — линия std::vector<person> personVect;, Вы пытались создать экземпляр vector<person>, Но person здесь неизвестно (т.е. не было объявлено в этой области) из-за (5). Это объясняет ваши две ошибки аргумента шаблона: vector<person> на самом деле неявно vector <person, allocator<person> >, Первый аргумент шаблона person а второй allocator<person>, поскольку person неизвестно, оба эти аргумента неверны.

Тот факт, что school.h включает в себя person.h, а person.h включает school.h, является причиной циклической зависимости, на которую вы ссылались. Чтобы избежать этого, нам нужен альтернативный способ объявить, что мы будем использовать определенный класс в файле. Общий подход заключается в использовании предварительная декларация — заявление class person; что я упомянул в решении, до определения school, Это обычное объявление, которое позволяет компилятору знать, что person (как используется в school класс) относится к классу.

Однако для того, чтобы построить vector<person>компилятору также нужно знать, сколько места занимает класс person занимает в памяти (т.е. его размер), который мы не предоставляем (и никогда не можем предоставить вручную) с объявлением class person;, Фактически, компилятор знает размер класса только после того, как было обработано полное определение в заголовочном файле. Но если мы попытаемся это сделать, мы вернемся к исходной точке (циклическая зависимость, а что нет). То, что мы знаем, это размер указатель в person, поскольку это зависит от компьютера (например, на 32-разрядной машине, размер указателя на что-нибудь 32 бита). Следовательно, мы можем создать экземпляр vector<person*> так как это всегда вектор 32-битных объектов, независимо от того, что person на самом деле

0

Вместо того, чтобы включить человека #include "person.h"
В заголовочном файле («school.h») просто напишите class person; и использовать указатель на person
А в модуле c ++ («school.cpp») включите «person.h», если вам нужно.

Это также будет иметь некоторые преимущества в функции. (сократить время компиляции)

Полезные ссылки:

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

0