Да, тема вопроса обсуждалась так много раз. И я почти понимаю эту разницу. У меня есть только одно сомнение, связанное с примером в книге.
Этот вопрос связан с моим предыдущим вопросом, где я представил 2 класса, взятых в качестве примера в книге С++ Primer.
В отношении этих классов в книге цитируется следующий абзац, специально связанный с объявлением функции-члена класса WindowManager
в качестве функции-друга. Вот что он говорит:
Создание функции-члена для друга требует тщательной структуризации наших программ для учитывать взаимозависимости между декларациями и определениями. В этом Например, мы должны заказать нашу программу следующим образом:
- Сначала определите класс Window_mgr, который объявляет, но не может определить, очистить. Экран должен быть объявлен до того, как clear сможет использовать элементы экрана.
- Далее, определите класс Screen, включая декларацию друга для очистки.
- Наконец, определите clear, который теперь может ссылаться на элементы в Screen.
Код, представленный мной в этом вопросе, следует только этой структуре. Но, похоже, он не работает. Это заставляет меня думать, если указанные выше пункты ошибочны, или я не реализовал его правильно.
Проблема заключается в том, что когда я объявляю функцию clear
функцией friend в классе ScreenCls
, я попадаю в циклическое включение файлов заголовков. Я еще раз расскажу о конкретной части обоих классов:
ScreenCls.h:
#ifndef SCREENCLS_H
#define SCREENCLS_H
#include <iostream>
#include "WindowManager.h"
using namespace std;
class ScreenCls {
friend void WindowManager::clear(ScreenIndex);
// Some other code
}
Здесь я должен включить заголовочный файл WindowManager.h
, так как функция clear
теперь использует ScreenIndex
, определенную там. Форвардная декларация не будет работать здесь (исправьте меня, если я ошибаюсь).
Теперь, перейдем к WindowManager.h
:
#ifndef WINDOWMANAGER_H
#define WINDOWMANAGER_H
#include <iostream>
#include <vector>
#include "ScreenCls.h"
using namespace std;
class WindowManager {
public:
// location ID for each screen on window
using ScreenIndex = vector<ScreenCls>::size_type;
private:
vector<ScreenCls> screens{ ScreenCls(24, 80, ' ') };
};
И сконцентрируйтесь на объявлении screens
здесь. Они использовали инициализатор списка для добавления значения по умолчанию ScreenCls
в vector
. Итак, здесь снова нужно включить WindowManager.h
. И теперь мы находимся в циклическом включении. Это предотвратит создание моего проекта.
Однако, если я изменяю объявление функции друга, чтобы сделать весь класс как друга, тогда я могу работать с forward declaring
классом WindowManager
. В этом случае он будет работать нормально.
Итак, в основном функция друзей здесь не работает, но класс друзей работает. Итак, так ли, что вышеупомянутые пункты не идут хорошо с их реализацией, или что-то не так с моими классами? Я просто хочу знать это, чтобы четко понять концепцию header inclusion
и forward declaration
.
Вопросы, связанные с моим предыдущим вопросом, описывают это хорошо. Но это просто, что он не работает в вышеуказанной ситуации, поэтому я снова прошу его.