Участник функции друга
Я пробовал несколько примеров в книге (С++ Primer от Stanley Lippman)
и я понимаю, что класс может сделать другой класс своим другом (доступ к некоторым частным членам). Теперь я читаю о том, что функция-член является другом, и я пробую пример
class Screen
{
public:
friend void Window_mgr::clear();
typedef std::string::size_type pos;
Screen () = default;
Screen (pos ht, pos wd, char c) : height (ht), width (wd),
contents (ht * wd, c) { }
private:
void do_display (std::ostream &os) const
{
os << contents;
}
pos cursor = 0;
pos height = 0, width = 0;
pos test_num = 100, test_num2 = 222;;
std::string contents = "contents";
};
class Window_mgr {
public:
using ScreenIndex = std::vector<Screen>::size_type;
void clear (ScreenIndex);
private:
std::vector <Screen> screens {Screen (24, 80, ' ')};
};
void Window_mgr::clear(ScreenIndex i)
{
Screen &s = screens[i];
s.contents = std::string(s.height * s.width, ' ');
}
но он создает ошибку компилятора, говоря
Window_mgr не объявлен
а затем я прочитал следующее:
• Сначала определите класс Window_mgr, который объявляет, но не может определить, очистить. Экран должен быть объявлен до того, как clear сможет использовать элементы экрана.
• Затем определите экран класса, включая декларацию друга для очистки.
• Наконец, определите четкость, которая теперь может относиться к членам на экране.
Я не понимаю эту часть - может кто-нибудь объяснить?
Ответы
Ответ 1
Когда компилятор доходит до friend void Window_mgr::clear();
, он понятия не имеет, что Window_mgr
, как он этого еще не видел. Вам нужно немного изменить порядок вещей, чтобы заставить это работать. сначала вы отправляете объявление Screen
, а затем у вас есть Window_mgr
class Screen;
class Window_mgr {
public:
using ScreenIndex = std::vector<Screen>::size_type;
void clear(ScreenIndex);
Window_mgr();
private:
std::vector <Screen> screens; // don't initialize here as we don't know what a screen actually is yet
//std::vector <Screen> screens {Screen (24, 80, ' ')}; can't do this as we don't what a Screen is here
};
Затем вы можете получить Screen
class
class Screen
{
public:
friend void Window_mgr::clear(ScreenIndex);
typedef std::string::size_type pos;
Screen() = default;
Screen(pos ht, pos wd, char c) : height(ht), width(wd),
contents(ht * wd, c) { }
private:
void do_display(std::ostream &os) const
{
os << contents;
}
pos cursor = 0;
pos height = 0, width = 0;
pos test_num = 100, test_num2 = 222;
std::string contents = "contents";
};
И тогда у вас могут быть части Window_mgr
, которые используют Screen
Window_mgr::Window_mgr() : screens{ Screen(24, 80, ' ') } {}
void Window_mgr::clear(ScreenIndex i)
{
Screen &s = screens[i];
s.contents = std::string(s.height * s.width, ' ');
}
Вы можете увидеть все это в этом живом примере
Ответ 2
Вы больше всего на пути, вам просто нужно убедиться, что вы объявите все свои классы и функции, прежде чем требовать это объявление.
В первой точке инструкции указано определение класса Window_mgr
, объявляющего Window_mgr::clear
. Чтобы использовать Screen
, этот класс также должен быть объявлен до Window_mgr
. Это выглядит так:
class Screen; //forward-declare Screen so that Window_mgr knows it exists
class Window_mgr {
public:
//requires forward declaration of Screen, like the above
using ScreenIndex = std::vector<Screen>::size_type;
void clear (ScreenIndex); //declare, but don't define, clear
};
Вторая точка говорит, чтобы определить Screen
и включить объявление друга для Window_mgr::clear
. Поскольку эта функция-член уже объявлена выше, это действительно:
class Screen
{
public:
using ScreenIndex = std::vector<Screen>::size_type;
//remember to friend with the same arguments
friend void Window_mgr::clear(ScreenIndex);
//...
};
В последнем пункте вы должны указать Window_mgr::clear
. Мы уже заявили в первом пункте, поэтому нам просто нужно сделать это:
void Window_mgr::clear(ScreenIndex i)
{
//...
}
Ответ 3
Одна из проблем заключается в том, что подпись ваших методов clear
отличается. Объявленный в классе Screen
принимает аргумент, а другой - нет. Подписи должны быть идентичными или язык на самом деле рассматривает их как разные функции.
Вторая проблема заключается в том, что ваша реализация конфликтует с вашей первой точкой: "определите класс Window_mgr
, который объявляет, но не может определить clear
". Ваш класс Window_mgr
объявляет и определяет clear
.