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

时间:2013-09-19 21:19:22

标签: c++ class friend forward-declaration

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

  

定义您自己的ScreenWindow_mgr版本,其中clearWindow_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, ' ');
}

现在这两个类,如果定义屏幕首先比Window_mgr工作,我预期。现在,练习要求我让clear成为Screen的朋友并定义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, ' ');
}

由于Window_mgr中的向量需要Screen为完整类型,这显然不起作用。这似乎是一个无法解决的练习,除非作者不打算使用他们之前出现的ScreenWindow_mgr类。

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

1 个答案:

答案 0 :(得分: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,其参数为不完整类型。它适用于大多数编译器(参见here为什么),但标准禁止它。

此示例演示如何使成员函数成为类的朋友:

#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);
}