这就是如果两个标头互相包含的话项目可能无法编译的原因吗?

问题描述 投票:0回答:1

我试图理解为什么两个相互包含的标头(每个标头包括另一个标头)不能按您预期的方式工作。我想知道我的推理是否正确:

如果你有 FooHeader.h:

#pragma once
#include "BarHeader.h"

struct Foo { Bar bar;};

还有一个 BarHeader.h:

#pragma once
#include "FooHeader.h"
struct Bar { Foo foo; };

可能无法编译的原因如下:

假设您有 main.cpp:

#include "BarHeader.h"

int main() { }

现在预处理器完成它的工作,替换“BarHeader.h”,使其看起来像这样:

|remove|
#include "BarHeader.h"

|add|
#include "FooHeader.h"
struct Bar { Foo foo; };

int main() {}

好的,这是第 1 步。但是预处理器还有工作要做,要替换“FooHeader.h”,所以下一步是:

|remove|
#include "FooHeader.h"

|add|
#include "BarHeader.h"
struct Foo { Bar bar;}



struct Bar { Foo foo; }

int main() {}

现在文件看起来像这样:

#include "BarHeader.h"


struct Foo { Bar bar;}

struct Bar { Foo foo; }

int main() {}

它仍然有一个包含,但是,由于该头文件已经被包含,所以它不再包含它,所以最终结果是:

struct Foo { Bar bar;}
    
struct Bar { Foo foo; }
    
int main() {}

这就是编译出现问题的原因吧?

如果预处理器只是将已包含的标头移动到文件中最高/第一次出现的位置,这是否就可以解决?所以像“我发现我已经把你包括在内,但你已经被包括在这里,所以我将它移到这里,然后一切都很好。”?这样就可以解决问题了吧?

c++ preprocessor circular-dependency
1个回答
0
投票
#include "BarHeader.h"

int main() { }

成为

// #include "BarHeader.h"
#pragma once // BarHeader
#include "FooHeader.h"
struct Bar { Foo foo; };

int main() { }

然后我们扩展#include指令

// #include "BarHeader.h"
#pragma once // BarHeader
// #include "FooHeader.h"
#pragma once // FooHeader
#include "BarHeader.h"

struct Foo { Bar bar;};
struct Bar { Foo foo; };

int main() { }

现在我们扩展

#include "BarHeader.h"
- 这不会执行任何操作,因为
#pragma once "BarHeader.h"
已经被评估,并且我们包含了
'BarHeader.h"

// #include "BarHeader.h"
#pragma once // BarHeader
// #include "FooHeader.h"
#pragma once // FooHeader
// #include "BarHeader.h"

struct Foo { Bar bar;};
struct Bar { Foo foo; };

int main() { }

我们得到一个错误。

您的规则“将其移至最早的位置”毫无意义 - 当我们遇到另一个 BarHeader.h 包含时,我们已经

已经
通过了
BarHeader.h
。 你无法“倒回”它。

处理它的技巧很容易理解。

此外,您的具体示例无法通过任何标头顺序来解决。 您不能在类 B 中包含类 A,因为 C++ 中的类是该类的实际实例而不是对该类的引用(如在 C#/Java/等中)。

预声明规则实际上是为了帮助避免循环结构定义。

© www.soinside.com 2019 - 2024. All rights reserved.