首页 > 解决方案 > 为什么在编译过程中会收到语法错误?

问题描述

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

在构建之前,我在 Visual Studio 2019 中没有收到任何错误,并且构建顺序似乎是bar, then foo, then 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;
}

标签: c++include

解决方案


概括:

  • foo.hpp包括bar.hppbar.hpp包括foo.hpp。这是一个循环依赖。
  • #pragma once如果它已经加载,请确保不要再次加载相同的标题。

  • 只有编译bar.cpp失败(foo.cpp并且main.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等),编译就会成功。


推荐阅读