会员功能朋友

Member function a friend

我一直在尝试书中的一些示例(Stanley Lippman 的 C++ Primer) 我知道 class 可以让另一个 class 成为朋友(访问一些私有成员)。现在我正在阅读有关成员函数成为朋友的信息,我尝试了示例

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 has not been declared

然后我读了这个:

• First, define the Window_mgr class, which declares, but cannot define, clear. Screen must be declared before clear can use the members of Screen.

• Next, define class Screen, including a friend declaration for clear.

• Finally, define clear, which can now refer to the members in Screen.

我不明白这部分 -- 谁能解释一下?

您已经完成了大部分工作,您只需要确保在需要声明之前声明所有 classes 和函数。

第一个指令点说定义 Window_mgr class 声明 Window_mgr::clear。为了使用 Screen,class 也必须在 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)
{
    //...
}

一个问题是您的 clear 方法的签名不同。在 Screen class 中声明的一个带参数,另一个不带参数。签名必须相同,否则语言实际上将它们视为不同的函数。

第二个问题是您的实现与第一点冲突:"define the Window_mgr class, which declares, but cannot define, clear." 您的 Window_mgr class 既声明又定义了 clear

当编译器到达 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
};

那你就可以拥有你Screenclass

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, ' ');
}

你可以看到这一切都在这个 live example