c++ - 为什么在编译过程中会收到语法错误?
问题描述
有人可以解释为什么我收到语法错误:在构建过程中没有包含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;
}
解决方案
概括:
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
等),编译就会成功。
推荐阅读
- c - 对 AND 位掩码感到困惑
- python - 自动将 SQL 查询转换为 python 代码
- excel - 图片类的粘贴/剪切方法在excel vb.net中失败
- jmeter - 为用户随机化用户名和相关的作业 ID
- reactjs - 将 react 与 django 集成
- c# - WPF:当 CollectionChanges 时绑定中断 - 为什么?
- laravel - 如何解决 Laravel + Nuxt.js 中的 CORS 错误
- c# - 什么是 Quaternion ,以及如何统一使用 Quaternion lerp?
- xcode - 安装 cocoapods 时出错/或如何安装 1.10.0 版本或最新版本的 cocoapods?
- python - 我怎样才能访问这个类的数据