Должен ли я помещать эти классы в их собственные заголовочные файлы? Если да, то как?

#c

Вопрос:

В главе 7.3.4 книги C Primer упоминаются прямые объявления и указание друзей функций-членов. В нем говорится, что определение друзей функций-членов требует тщательной структуры для учета взаимозависимости между объявлениями и определениями. Когда я снимаю весь пух, вот результат:

 #include <string>
#include <vector>

class Screen;

class Window_mgr {
public:
    using ScreenIndex = std::vector<Screen>::size_type;
    void clear(ScreenIndex);
private:
    std::vector<Screen> screens;
};

class Screen {
    friend void Window_mgr::clear(ScreenIndex);
public:
    using pos = std::string::size_type;
private:
    pos height{0},
        width{0};
    std::string contents;
};

inline void Window_mgr::clear(ScreenIndex i) {
    Screenamp; s = screens[i];
    s.contents = std::string(s.height * s.width, ' ');
}
 

Насколько я понимаю, классы помещаются в свои собственные заголовочные файлы. Если это так, то как мне их разделить? Я проверил некоторые вопросы о переполнении стека, но не нашел ответа, который ищу.

Правка: вот как мне удалось очистить код, но я все еще не уверен, хорошо ли это из-за плохой практики и возможно ли это вообще поддерживать.

window_mgr.h

 #ifndef WINDOW_MGR_H
#define WINDOW_MGR_H

#include <vector>

class Screen;

class Window_mgr {
public:
    using ScreenIndex = std::vector<Screen>::size_type;
    void clear(ScreenIndex);
private:
    std::vector<Screen> screens;
};

#endif
 

screen.h

 #ifndef SCREEN_H
#define SCREEN_H

#include <string>

#include "window_mgr.h"

class Screen {
    friend void Window_mgr::clear(ScreenIndex);
public:
    using pos = std::string::size_type;
private:
    pos height{0},
        width{0};
    std::string contents;
};

#endif
 

window_mgr.cpp

 #include "window_mgr.h"
#include "screen.h"

inline void Window_mgr::clear(ScreenIndex i) {
    Screenamp; s = screens[i];
    s.contents = std::string(s.height * s.width, ' ');
}
 

Комментарии:

1. void Window_mgr::clear(ScreenIndex i) вошел бы в Window_mgr.cpp

2. Возьмите объявление класса в заголовок и определение методов в файле cpp. В большинстве случаев у вас будет меньше проблем с включениями, когда каждый класс находится в отдельном .h/.cpp файл.

3. «Насколько я понимаю, классы помещаются в свои собственные заголовочные файлы». Необязательно. C — это не Java. Вы можете разместить в одном заголовке столько классов, сколько захотите, и часто «по одному классу на файл» очень непрактично

4. @Jarod42 Зачем этой функции нужна собственная единица перевода?

5. Решение — избегайте друзей, позвольте Screen определить, как он очищается, и позвольте Window_mgr использовать эту общедоступную функциональность Screen

Ответ №1:

Как бы то ни было…

Мне никогда не приходилось использовать методы друзей, кроме оператора< Если вы добавляете геттеры в личные поля, то вашему методу Window_mgr не обязательно быть другом, и вы устраняете циклическую зависимость.