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

时间:2019-11-03 05:13:55

标签: c++ include

有人可以解释为什么我收到语法错误:在构建过程中在class Bar;头文件中没有包含foo.hpp的情况下,标识符'Bar'吗?

在构建之前,我没有在Visual Studio 2019中收到任何错误,并且构建顺序似乎依次为bar,然后依次为foomain,所以依次跟随{{1 }}语句,好像#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;
}

2 个答案:

答案 0 :(得分:1)

摘要:

  • foo.hpp包括bar.hpp,而bar.hpp包括foo.hpp。这是周期性的依赖关系。
  • #pragma once确保不再加载相同的标头(如果已加载)。

  • bar.cpp的编译失败(foo.cppmain.cpp将被成功编译)

在编译bar.cpp时,请遵循预处理程序。事情按以下顺序发生。

  1. bar.cpp包括bar.hpp
  2. bar.hpp包括foo.hpp。 (注意以下两点)
    • 预处理器会记住它输入了bar.hpp,并将避免在当前循环中再次输入它。
    • 符号Bar(类Bar的声明)仍未加载,因为之前已包含foo.hpp
  3. foo.hpp尝试包含bar.hpp
    • 预处理器知道它已经输入bar.hpp,因此将其忽略!
    • 但是,Foo类声明使用称为Bar的符号。但这没有在之前声明!

未知符号Bar可能表示很多东西(类,宏等)。因此,编译器(正确地)失败了,因为它不知道如何处理它。

解决方案是前向声明。在那里,您可以保证编译器Bar代表一个类。只要您没有在编译器需要了解类布局的地方做任何事情(例如,定义类型为Bar的成员函数,访问Bar的成员函数等),编译就会成功。

答案 1 :(得分:0)

foo.hppbar.hpp彼此不依赖,因此前向声明是避免其头文件之间循环依赖的好方法。实际上,只有.cpp个文件需要同时包含两个头文件。