2013-03-28 158 views
0

我的搜索让我相信我遇到的问题被称为循环冗余。我不明白任何发布的解决方案。我是C++的(相当)新手,来自强大的Java背景。C++类相互依赖导致循环依赖性错误

基本上有两个类彼此依赖。 A类包含B类对象的向量,而B类包含需要A类对象作为输入的方法。

下面是重现问题的代码。

根据codelite g ++,错误在school.h中,并且“person没有在此范围内声明”。它还说“模板参数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

你忘了问一个问题。是“如果我需要这种功能,我该怎么办?”? – Vesper 2013-03-28 06:16:20

回答

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

这不起作用。因为他使用实例而不是指针 – Eran 2013-04-02 18:28:43

+0

是的,谢谢。我已经更新了这个问题。 – azat 2013-04-02 20:17:22

3

的问题可以通过更好的设计,你阶级关系来解决。

A Person不是由School组成,所以它不需要有学校成员。

A School有一个Person对象的集合。

如果你想要一个人对学校做些什么,把它作为一个论点。这样你可以使用指针转发声明来解决这个问题。

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

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

试试这个,

人。^ 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。由于您以前从未包含过,PERSON_H尚未定义,并且ifndef PERSON_H当前为真。所以我们去文件中的下一行。

  2. 这种情况发生在此文件中的第一个有趣的是,PERSON_H被定义(#fdefine PERSON_H)。下一次你使用这个文件时,预处理器会跳过整个文件,直接到#endif。

  3. 第二有趣的事情发生是,school.h被包括在内。所以预处理器找到了school.h(我们还没有处理学校课程!),直到现在还没有处理过。

  4. 在school.h第一个有趣的事情(#定义SCHOOL_H后)为的#include person.h,所以预处理器回报到person.h(我们还没有处理的Person类无论是!)。但是这次PERSON_H已经被定义了,所以#ifndef PERSON_H是false,并且预处理器跳到那个文件中的#endif(正如我在(2)中提到的那样)。所以Person类还没有被宣布。

  5. 我们返回school.h,什么也没做。此时,我们即将宣布/定义学校课程。人类有从未被宣布为,因为我们的预处理器从person.h跳到了school.h,返回到person.h到了school.h,只处理了#include指令。

  6. 编译器开始通过school类定义。下一个有趣的事情是行std::vector<person> personVect;。您试图实例化一个vector<person>。但是由于(5),这里是person这是未知的(即未在此范围内声明)。这解释了您的两个模板参数错误:A 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