У меня есть два класса, которые определены в отдельных файлах заголовков. Каждый файл имеет поле, которое является типом другого класса. Теперь я включил в заголовок каждого файла заголовок другого файла, но компилятор генерирует ошибки. Что мне не хватает?Файлы заголовков C++, включая друг друга, взаимно
ответ
Вы не можете иметь в каждом классе «поле, которое является типом другого класса»; это было бы рекурсивным определением, и не только компилятор не смог бы сделать из этого никакого смысла, он даже не имеет логического смысла.
Каждый класс, имеющий поле, которое является типом другого класса, является видом невозможности, которую вы видите только в M.C. Эшера чертежи, или анимации их, как этот:
Источник: escherdroste.math.leidenuniv.nl
на основе Эшера «Print Gallery» Литография, 1956, see Wikipedia
Одно из двух полей должны быть указателем, чтобы сломать рекурсивное сдерживание, и избегайте логической невозможности.
Это приводит нас к следующей проблеме: если класс B должен содержать экземпляр класса A, то, очевидно, A должен быть объявлен перед классом B, так что A уже известно компилятору при компиляции B. Но если класс A объявлен перед классом B, как мы можем объявить указатель на B в A? Класс B пока неизвестен в то время, когда A скомпилирован! Ответ на это - это специальная конструкция, известная как форвардная декларация, которая существует именно для того, чтобы приспособить такие ситуации. Передняя декларация класса B выглядит следующим образом:
class B;
Все это говорит компилятор, что будет класс называется B. Он не говорит компилятор ничего о содержимом класса B, так что есть очень мало мы можем сделать с ним, но мы можем сделать одну вещь: объявить указатели В.
Таким образом, полное решение проблемы выглядит следующим образом:
файл «Ах»:
/* This is called a "forward declaration". We use it to tell the compiler that the
identifier "B" will from now on stand for a class, and this class will be defined
later. We will not be able to make any use of "B" before it has been defined, but
we will at least be able to declare pointers to it. */
class B;
class A
{
/* We cannot have a field of type "B" here, because it has not been defined yet.
However, with the forward declaration we have told the compiler that "B" is a
class, so we can at least have a field which is a pointer to "B". */
B* pb;
}
файл «B.h»:
#include "A.h"
class B
{
/* the compiler now knows the size of "A", so we can have a field of type "A". */
A a;
}
[Источник анимации] (http://escherdroste.math.leidenuniv.nl/index.php?menu=animation) – Potatoswatter
@Potatoswatter благодарит! Я изменил заголовок изображения. –
Вы не должны включать файлы заголовков внутри других, просто укажите файлы заголовков в исходные файлы.
В заголовках можно использовать опережающее объявление:
// In Class1.h
class Class2;
// In class2.h
class Class1;
Также вы можете защитить от файла включаются дважды с использованием препроцессора:
// Class1.h
#ifndef __CLASS_1_H
#define __CLASS_1_H
// content
#endif
ПРИМЕЧАНИЕ: форвардные объявления означают, что вы можете использовать этот класс только как указатель в файле заголовка. Не экземпляр класса. –
Хорошо, я забыл упомянуть об этом! –
Вы также можете использовать его как тип возврата или тип параметра в объявлении функций и как часть ссылочного типа. –
Вы, вероятно, хотите использовать вперед декларацию, если вы действительно не хотите помещать экземпляр каждого класса друг в друга. В этом случае вы ничего не должны использовать.
Я знаю, что это старая тема, но, может быть, вы все еще заинтересованы в решении!
Фактически на C++ вы можете использовать два класса рекурсивно, не используя указатели, и вот как это сделать.
файл: хиджры
#include <b.h>
class A {
B<> b;
}
файл: b.h
class A;
template<typename T = A>
class B {
T a;
}
файла: main.cpp
#include "a.h"
A a;
и это все!
, конечно, это только для любопытства :)
Я дам вам +1 для этого :-) – MegaManX
Спасибо, это твой вид :) – Boynux
Вы пытались его скомпилировать? MSVC дает мне ошибку: «B :: a» использует неопределенный класс «A» ' – kinokijuf
- 1. Файлы заголовков C++, включая друг друга
- 2. C++: Включая файлы заголовков друг в друга
- 3. Заголовочные файлы, включая друг друга
- 4. Включая файлы заголовков C++
- 5. Включая файлы заголовков в C
- 6. C - заголовки, включая друг друга probem
- 7. Включая файлы заголовков (включая самих себя)
- 8. Включая модели obj wavefront друг в друга
- 9. Включая JS-файлы внутри друг друга через Grunt без Require.js
- 10. Файлы, не дожидаясь друг друга
- 11. Включая файлы заголовков C из другого каталога
- 12. Включая файлы заголовков в VS2005
- 13. Заказ нескольких массивов (включая друг друга)
- 14. MinGW и JDK взаимно отключают исполняемые файлы друг друга в пути
- 15. Взаимоисключающие функции, вызывающие друг друга
- 16. Включая файлы заголовков в статическую библиотеку
- 17. включая файлы заголовков, получающие ошибки компиляции
- 18. Включая все файлы заголовков в приложении
- 19. Включая файлы заголовков рекурсивно для синтаксиса
- 20. Избежать классов, не видящих друг друга? C++
- 21. внешние js-файлы не знают друг друга
- 22. (расположенных в различных заголовков), которые используют друг друга объекты
- 23. Включая файлы заголовков более одного раза
- 24. Включая файлы заголовков в Xcode 4
- 25. Включая файлы заголовков, когда нет файла реализации?
- 26. Включая определенные файлы заголовков в yocto build
- 27. включая общие файлы заголовков в файле .pch
- 28. Включая файлы заголовков в C++ (определение класса и реализация метода)
- 29. Файлы заголовков C++ простой вопрос
- 30. Заголовки, нуждающиеся друг друга
Какое «поле»? – fge