Почему заголовочные файлы не могут включать друг друга?
Почему я не могу сделать что-то подобное в C++?
A. h:
#ifndef A_H
#define A_H
#include "B.h"
struct A {
int a;
};
void doStuff1 (B b); // Error here
#endif
B. h:
#ifndef B_H
#define B_H
#include "A.h"
struct B {
int b;
};
void doStuff2 (A a); // Error here
#endif
Я получаю ошибку, что 'A' was not declared in this scope
и то же самое с 'B'
.
Я знаю о прямом объявлении, но я хотел посмотреть, можно ли настроить такой параметр как pass-by-value вместо ссылки/указателя. Почему компилятор ведет себя подобным образом, если и A
, и B
фактически объявляются к тому моменту, когда компилятор достигает этого кода?
2 ответа:
Основной урок: Includes обрабатываются до того, как любой C++ будет проанализирован. Они обрабатываются предкомпилятором.
Предположим, что
A.h
оказывается включенным доB.h
. Вы получите что-то вроде этого:#ifndef A_H #define A_H // ----- B.h include ----- #ifndef B_H #define B_H #include "A.h" // A_H is defined, so this does nothing struct B { int b; }; void doStuff2 (A a); // Error here #endif // ----- B.h include ----- struct A { int a; }; void doStuff1 (B b); // Error here #endif
В этот момент компилятор C++ может взять на себя и начать разбор вещей. Он попытается выяснить, что такое параметр to
doStuff2
, ноA
еще не определен. Та же самая логика верна и в обратном направлении. В обоих случаях у вас есть зависимости от типов, которые еще не определились.Все это просто означает, что ваши зависимости вышли из строя. Это не проблема с проходным значением. Ваши типы должны быть определены до ваших методов. Вот и все-смотрите пример ниже.
// Example program #include <iostream> #include <string> // data_types.h struct A { int x; }; struct B { int y; }; using namespace std; // methods_A.h void foo(A a) { a.x = 3; cout << "a: " << a.x << endl; } // methods_B.h void bar(B b) { b.y = 4; cout << "b: " << b.y << endl; } int main() { A first; B second; first.x = 0; second.y = 100; foo(first); bar(second); cout << "A: " << first.x << ", B: " << second.y << endl; }
Пример вывода
a: 3 b: 4 A: 0, B: 100
У вас есть круговое включение. Вам нужно либо разделить их на разные заголовочные файлы, например, иметь
A.h
иB.h
только объявление структуры/классов и иметь другой заголовочный файл, объявляющий функции.Проблема также может быть решена с помощью прямых объявлений и передачи по ссылке вместо этого:
struct A; struct B; void doStuff1(A& a); void doStuff2(B& b);