为啥在编译过程中会收到语法错误?
Posted
技术标签:
【中文标题】为啥在编译过程中会收到语法错误?【英文标题】:Why do I receive a syntax error during compilation?为什么在编译过程中会收到语法错误? 【发布时间】:2019-11-03 05:13:55 【问题描述】:有人可以解释为什么我在构建过程中收到语法错误:标识符“Bar”,而foo.hpp
头文件中没有包含class Bar;
?
在构建之前,我在 Visual Studio 2019 中没有收到任何错误,构建顺序似乎是 bar
,然后是 foo
,然后是 main
,因此遵循 #include
语句看起来好像在构建过程中,bar
头文件首先包含在 foo
头中。
我在下面包含了概述基本问题的代码。
//Foo header file
#pragma once
#include "bar.hpp"
#include <iostream>
class Bar; //Commenting this line out results in no longer being able to build the project
class Foo
public:
Foo();
void pickSomething(Bar& bar);
;
//Foo cpp file
#include "foo.hpp"
Foo::Foo()
std::cout << "Made Foo" << std::endl;
void Foo::pickSomething(Bar& bar)
bar.getSomething();
std::cout << "Picked something!" << std::endl;
//Bar header file
#pragma once
#include "foo.hpp"
#include <iostream>
class Foo;
class Bar
public:
Bar(Foo& foo);
void getSomething();
;
//Bar cpp file
#include "bar.hpp"
Bar::Bar(Foo& foo)
std::cout << "Made bar" << std::endl;
void Bar::getSomething()
std::cout << "Gave something!" << std::endl;
//main file
#include "foo.hpp"
#include "bar.hpp"
int main()
Foo foo;
Bar bar(foo);
foo.pickSomething(bar);
return 0;
【问题讨论】:
您是否在构建期间收到这些错误,或者它们在代码侧边栏中突出显示? 我只在构建期间收到它们。 看来你有一个循环包含。如果 file2 包含 file1,则 file1 不能包含 file2。 假设这两个类以原始代码的方式相互依赖,那么组织文件的正确方法是什么? foo 和 bar 是否应该在单个标题中定义?不知何故,这感觉像是一种糟糕的做法。 参见this answer 以了解非常相似的案例。 【参考方案1】:总结:
foo.hpp
包括 bar.hpp
和 bar.hpp
包括 foo.hpp
。这是一个循环依赖。
#pragma once
确保不会再次加载相同的标头(如果已加载)。
只有bar.cpp
编译失败(foo.cpp
和main.cpp
会编译成功)
让我们在编译bar.cpp
的时候跟随预处理器。事情按以下顺序发生。
bar.cpp
包括 bar.hpp
bar.hpp
包括 foo.hpp
。 (注意以下两点)
预处理器记住它输入了bar.hpp
,并将避免在当前循环中再次输入它。
符号Bar
(类Bar
)仍未加载,因为之前包含foo.hpp
foo.hpp
尝试包含 bar.hpp
预处理器知道它已经输入了bar.hpp
,因此它被忽略了!
但是,Foo
类声明使用一个名为 Bar
的符号。但这不是之前声明的!
未知符号Bar
可以代表很多东西(类、宏等)。所以编译器(正确地)失败了,因为它不知道如何处理它。
解决方案是前向声明。在那里,您向编译器保证符号 Bar
代表一个类。只要您不做任何编译器需要了解类布局的事情(例如定义Bar
类型的成员函数、访问Bar
的成员等...),编译就会成功。
【讨论】:
出于好奇,如果编译器确实需要了解类布局,那么最好的补救措施是什么? IMO,这需要由设计级别处理,因为它可能表明存在设计问题。但请注意,如果您使用指针成员,前向声明就足够了。取消引用指针时,您只需要源文件中的完整定义。所以通常这样的问题可以通过这种方式轻松解决。【参考方案2】:foo.hpp
和 bar.hpp
不相互依赖,因此前向声明是避免其头文件之间循环依赖的好方法。只有.cpp
文件实际上需要包含这两个头文件。
【讨论】:
以上是关于为啥在编译过程中会收到语法错误?的主要内容,如果未能解决你的问题,请参考以下文章
Postgresql: 在 ""ViewShifts"" 处或附近出现语法错误 为啥我在下面的查询中会出现此错误?
如何修复WordPress网站的Syntax Errors语法错误