我正在尝试将以下两个类分开,以便每个类都可以在自己的标题中定义:
#include <iostream>
class Boo;
class Foo
{
public:
Foo(Boo *booPtr)
:booPtr(booPtr){};
virtual ~Foo(){};
Boo *booPtr;
};
class Boo
{
public:
Boo()
:foo(this){};
virtual ~Boo(){};
Foo foo;
int num = 32;
};
int main()
{
Boo *boo = new Boo;
std::cout << "booPtr : " << boo->foo.booPtr->num << '\n';
delete boo;
}
booPtr : 32
Program ended with exit code: 0
这是我分离失败的尝试:
"Foo.hpp"
#ifndef Foo_hpp
#define Foo_hpp
#include <stdio.h>
#include "Boo.hpp"
class Foo
{
public:
Foo(Boo *booPtr)
:booPtr(booPtr){};
virtual ~Foo(){};
Boo *booPtr;
};
#endif /* Foo_hpp */
"Boo.hpp"
#ifndef Boo_hpp
#define Boo_hpp
#include <stdio.h>
#include "Foo.hpp"
class Boo
{
public:
Boo()
:foo(this){};
virtual ~Boo(){};
Foo foo; // Error : Field has incomplete type 'Boo'
int num = 32;
};
#endif /* Boo_hpp */
"main.cpp"
#include <iostream>
#include "Foo.hpp"
#include "Boo.hpp"
int main()
{
Boo *boo = new Boo;
std::cout << "booPtr : " << boo->foo.booPtr->num << '\n';
delete boo;
}
但是我无法构建代码,因为它会产生以下错误:
Boo.hpp-> Foo foo; ->“字段的类型'Boo'不完整”
如何修复我的代码?
答案 0 :(得分:2)
您拥有一个包含另一个文件的文件,反之亦然。这创建了一个包含的循环。
认识到#include
宏除了将自身(即,它的行)替换为另一个文件外什么也不做。这很明显为什么您不能拥有文件A的包含文件B。
显而易见的解决方案是在Foo中预先声明Boo:
#ifndef Foo_hpp
#define Foo_hpp
#include <stdio.h>
class Boo;
class Foo
{
public:
...
奇怪的是,在分离它们之前,您已经这样做了。
现在为您提供更多理论:从技术上讲,一类是数据存储。它需要知道它的大小才能保留内存。因此,它需要知道其成员的所有大小,只有在声明它们时才能知道。因此,一个类需要包含其作为成员的每个类的声明标头。但是,指向对象的指针是不同的(引用也一样)。指针始终采用相同的大小,即32或64位,具体取决于您的平台(由于当前我们有64位平台,因此可能为64位)。因此,该类不需要知道它指向的类,它为其指针成员保留的内存始终是相同大小的。这就是为什么在这里没有任何关于类大小的正向声明的原因。
答案 1 :(得分:2)
虽然循环包含本身(假设适当的包含保护)不是错误,但请记住,它只是文本替换:
确保所有排列都是可行的,并且具有相同的含义!
在您的情况下,将"Boo.hpp"
的包含替换为您在合并源中使用的前向声明。
或者,您知道,只需放弃拆分标题即可:
请记住,类不一定是组织的适当单位。
答案 2 :(得分:1)
以Foo.hpp开头的通函包含附录
#ifndef FOO
#define FOO // (!)
// now including BOO!
#ifndef BOO
#define BOO
// now including FOO a g a i n
// as FOO i s already defined, all that remains is:
#ifndef FOO
#endif
class Boo { }; // now lacking definition of Foo...
#endif // BOO
class Foo { };
#endif // FOO (first one)
类似地,对于Boo.hpp(您只需要预先声明Foo,但是没有,因为之后的定义再次出现...)。
如您所见,通函包括,提供了适当的包括保护措施,不会导致无限的自我接纳。但是,结果却不是您想要的。