如何声明两个类,使A有B和B的成员将A的成员标记为朋友?

Ada*_*dam 6 c++ class friend forward-declaration

我试图从C++ Primer第5版开始练习7.32.该练习要求如下:

定义你自己的版本Screen,并Window_mgr在其中clear的成员Window_mgr和朋友Screen.

下面是定义Screen,Window_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, ' ');
}
Run Code Online (Sandbox Code Playgroud)

现在这两个类,如果定义屏幕首先比Window_mgr工作,我预期.现在,练习要求我成为clearScreen的朋友并定义clear.要使clear一个成员成为朋友,如果我理解正确,Window_mgr必须定义.要定义Window_mgr,Screen必须定义.这对我来说似乎不可能.

该文本提供以下提示:

使成员函数成为朋友需要仔细构造我们的程序以适应声明和定义之间的相互依赖性.在这个例子中,我们必须按如下方式订购我们的程序:

  • 首先,定义Window_mgr声明但未定义的类clear.Screen必须在clear使用之前声明Screen.

  • 接下来,定义类Screen,包括友元声明clear.

  • 最后,定义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, ' ');
}
Run Code Online (Sandbox Code Playgroud)

这显然是行不通的,因为其中的向量Window_mgr需要Screen是一个完整的类型.这似乎是一个无法解决的运动,除非作者不打算一个使用ScreenWindow_mgr班他们更早出现.

还有其他人从C++ Primer解决了这个练习.如果是这样,怎么样?任何帮助如何做到这一点,或者我的直觉告诉我,不能做到这一点?

BЈо*_*вић 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);
}
Run Code Online (Sandbox Code Playgroud)

请注意,不可能解决该练习,因为 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);
}
Run Code Online (Sandbox Code Playgroud)