将耦合 类 拆分为单独的 headers

Splitting coupled classes into separate headers

我正在尝试将以下两个 class 分开,以便每个 class 都可以在其自己的 Header:

中定义
#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; -> "Field has incomplete type 'Boo'"

如何修复我的代码?

您有一个文件包含另一个文件,反之亦然。这创造了一个包容的循环。

意识到 #include 宏除了用其他文件替换自身(即它的行)之外什么都不做。这很明显为什么你不能让文件 A 包含文件 B.

显而易见的解决方案是在 Foo 中对 Boo 进行前向声明:

#ifndef Foo_hpp
#define Foo_hpp

#include <stdio.h>
class Boo;

class Foo
{
public:
...

奇怪的是,你在分开它们之前就已经这样做了。

现在为您提供更多理论:class 在技术上是一种数据存储。它需要知道它的大小才能保留内存。因此,它需要知道它的成员的所有大小,只有在声明它们时才能知道。因此,class 需要包含它作为成员的每个 class 的声明 headers。但是,指向 object 的指针是不同的(引用也是如此)。指针总是采用相同的大小,即 32 位或 64 位,具体取决于您的平台(可能是 64 位,因为我们现在有 64 位平台)。因此,class 不需要知道它指向的 class,它为其指针成员保留的内存大小始终相同。这就是为什么前向声明在这里没有任何关于 classes 大小的问题。

虽然循环包含本身,正确的 include-guards 假定,不是错误,但请记住它只是文本替换:

确保所有的排列都是可行的并且具有相同的含义!

在您的情况下,将包含的 "Boo.hpp" 替换为 forward-declaration,您出于某种原因在合并源中使用了它。

或者,您知道,干脆放弃拆分 header:
请记住,类 不一定是正确的组织单位。

通告的附录包括,从 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,但有 none,因为之后的定义再次出现...)。

如您所见,循环包含,提供适当的包含守卫,不会导致无休止的自我包含。然而,结果并非如你所愿。