为啥在编译过程中会收到语法错误?

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.hppbar.hpp 包括 foo.hpp。这是一个循环依赖。

#pragma once 确保不会再次加载相同的标头(如果已加载)。

只有bar.cpp编译失败(foo.cppmain.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.hppbar.hpp 不相互依赖,因此前向声明是避免其头文件之间循环依赖的好方法。只有.cpp 文件实际上需要包含这两个头文件。

【讨论】:

以上是关于为啥在编译过程中会收到语法错误?的主要内容,如果未能解决你的问题,请参考以下文章

Postgresql: 在 ""ViewShifts"" 处或附近出现语法错误 为啥我在下面的查询中会出现此错误?

为啥我会收到此语法错误? (Python)

为啥我会收到语法错误:SassError:预期的“”?

如何修复WordPress网站的Syntax Errors语法错误

为啥我从 tensorflow 网站收到此代码的语法错误? [关闭]

为啥我会收到这个语法错误(false syntax error pyflakes)