会员功能的朋友

时间:2015-07-10 14:05:10

标签: c++ class friend

我一直在尝试书中的一些例子(Stanley Lippman的C ++ Primer) 我理解一个类可以使另一个类成为它的朋友(访问一些私有成员)。现在我正在阅读一个成员函数作为朋友,我尝试了这个例子

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之前声明屏幕才能使用Screen的成员。

     

•接下来,定义类屏幕,包括明确的朋友声明。

     

•最后,明确清楚,现在可以引用屏幕中的成员。

我不明白这一部分 - 有人可以解释一下吗?

3 个答案:

答案 0 :(得分:3)

你大部分都在那里,你只需要确保在需要声明之前声明所有的类和函数。

第一个指令点表示定义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)
{
    //...
}

答案 1 :(得分:2)

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

中查看所有内容

答案 2 :(得分:1)

一个问题是clear方法的签名有所不同。在Screen类中声明的那个接受一个参数,而另一个没有。签名必须相同,或者语言实际上将它们视为不同的功能。

第二个问题是你的实现与你的第一点冲突:&#34;定义Window_mgr类,它声明但不能定义clear。&#34;您的Window_mgr类都声明并定义clear