6

我正在尝试从 C++ Primer 5th Edition 做练习 7.32。该练习要求以下内容:

定义您自己的版本,Screen其中Window_mgrclear的成员Window_mgr和朋友Screen

以下是 的定义ScreenWindow_mgrclear在正文中给出。

class Screen
{
  public:
    using pos = std::string::size_type;
    Screen(pos ht, pos wd, char c) : height(ht), width(wd), contents(ht * wd, c) { }
  private:
    pos height = 0, width = 0;
    std::string 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, ' ');
}

现在这两个类,如果先定义 Screen 而不是 Window_mgr 可以按我的预期工作。现在,练习要求我结交clearScreen 的朋友并定义clear. 让clear会员成为朋友,如果我理解正确,Window_mgr必须定义。要定义Window_mgrScreen必须定义。这对我来说似乎是不可能的。

文本给出了以下提示:

使成员函数成为朋友需要仔细构造我们的程序以适应声明和定义之间的相互依赖关系。在这个例子中,我们必须对我们的程序进行如下排序:

  • 首先,定义Window_mgr类,该类声明但不定义clear. Screen必须在clear可以使用 的成员之前声明Screen

  • 接下来,定义 class Screen,包括为clear.

  • 最后是 define clear,它现在可以引用Screen.

我试图解决这个练习的顺序最终是这样的:

class Screen;

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

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

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

这显然是行不通的,因为其中的向量Window_mgr需要Screen是一个完整的类型。这似乎是一个无法解决的练习,除非作者不打算使用他们之前介绍ScreenWindow_mgr类。

有没有其他人从 C++ Primer 中解决了这个练习。如果是这样,怎么做?任何帮助如何做到这一点,或者正如我的直觉告诉我的那样,无法做到?

4

1 回答 1

3

正如 [class.friend]/5 所说:

当友元声明引用重载名称或运算符时,只有参数类型指定的函数成为友元。类 X 的成员函数可以是类 Y 的朋友。

在您的具体情况下:

#include <iostream>
#include <vector>

struct Screen;

class Window_mgr
{
  public:

    Window_mgr();

    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;
    Screen(pos ht, pos wd, char c) : height(ht), width(wd), contents(ht * wd, c) { }
  private:
    pos height = 0, width = 0;
    std::string contents;
};


Window_mgr::Window_mgr():
  screens{1, Screen(24, 80, ' ') }
{
}

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

int main()
{
  Window_mgr w;
  w.clear(0);
}

请注意,无法解决该练习,因为 Window_mgr 具有 std::vector 的成员变量,其参数是不完整的类型。它适用于大多数编译器(见这里为什么),但标准禁止它。

这个例子演示了如何使一个类的成员函数成为朋友:

#include <iostream>

struct A;

struct B
{ 
  void bar( A& a, int l);
};

struct A
{
  friend void B::bar(A&,int);
  A():k(0){}
  private:
  void foo(int m);
  int k;
};



void A::foo(int m)
{
  std::cout<<"A::foo() changing from "<<k<<" to "<<m<<std::endl;
  k=m;
}

void B::bar( A& a, int l)
{
  std::cout<<"B::bar() changing to "<<l<<std::endl;
  a.foo(l);
}

int main()
{
  A a;
  B b;
  b.bar(a,11);
}
于 2013-09-19T21:30:17.943 回答