我正在尝试做 C++ Primer 第 5 版中的练习 7.32。该练习要求以下内容:
Define your own versions of
Screen
andWindow_mgr
in whichclear
is a member ofWindow_mgr
and a friend ofScreen
.
下面是文中给出的Screen
、Window_mgr
和clear
的定义。
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,则按我预期的那样工作。现在,练习要求我使 clear
成为 Screen 的友元并定义 clear
。要使明确
一个成员成为 friend ,如果我理解正确的话,必须定义Window_mgr
。要定义 Window_mgr
,必须定义 Screen
。这对我来说似乎是不可能的。
文中给出了以下提示:
Making a member function a friend requires careful structuring of our programs to accommodate interdependencies among the declarations and definitions. In this example, we must order our program as follows:
First, define the
Window_mgr
class, which declares, but does not define,clear
.Screen
must be declared beforeclear
can use members ofScreen
.Next, define class
Screen
, including a friend declaration forclear
.Finally, define
clear
, which can now refer to members inScreen
.
我尝试解决这个练习的顺序最终是这样的:
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
中的 vector 需要 Screen
是一个完整的类型。这似乎是一项无法解决的练习,除非作者不打算使用他们之前提供的 Screen
和 Window_mgr
类。
有没有其他人通过 C++ Primer 解决了这个练习。如果是这样,如何?任何帮助如何做到这一点,或者正如我的直觉告诉我,不能做到这一点?
最佳答案
正如 [class.friend]/5 所说:
When a friend declaration refers to an overloaded name or operator, only the function specified by the parameter types becomes a friend. A member function of a class X can be a friend of a class 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);
}
关于c++ - 如何声明两个类使得 A 具有 B 的成员并且 B 将 A 的成员标记为 friend ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18905090/