成员函数作为朋友:利普曼第五本书错了吗?



Lippman 5th 国际标准书号-13: 978-0321714114

第280-281页,它说:

使成员函数成为朋友

与其让整个Window_mgr班成为朋友,屏幕可以 而是指定仅允许 Clear 成员访问。当我们 声明一个成员函数是朋友,我们必须指定 该函数是哪个成员:

class Screen {
// Window_mgr::clear must have been declared before class Screen
friend void Window_mgr::clear(ScreenIndex);
// ... rest of the Screen class
};

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

  • 首先,定义 Window_mgr 类,该类声明但无法定义 clear。必须先声明屏幕,然后清除才能使用 屏幕的成员。
  • 接下来,定义类 Screen,包括用于清除的好友声明。
  • 最后,定义 clear,现在可以引用屏幕中的成员。

问题是:类Window_mgr有一个依赖于类的数据成员 屏幕定义。看:

class Window_mgr {
public:
// location ID for each screen on the window
using ScreenIndex = std::vector<Screen>::size_type;
// reset the Screen at the given position to all blanks
void clear(ScreenIndex);
private:
std::vector<Screen> screens{Screen(24, 80, ' ')};
};

所以不可能首先定义Window_mgr而不定义屏幕 以前! 同时,如果没有我们有,就不可能定义屏幕 定义的Window_mgr!!!

如何解决这个问题??? 这本书错了吗?

我将在此处粘贴一个代码,以便您可以使用 最小代码:

#include <iostream>
#include <string>
#include <vector>
class A
{
friend void B::hello();
public:
A(int i) : number{i} {}
private:
void f() {
std::cout << "hello" << std::endl;
}
int number;
};
class B {
private:
std::vector<A> x{A(10)};
public:
void hello()
{
for(A &elem : x)
{
elem.f();
}
}
};

int main()
{
A x;
return 0;
}

如果我编译此代码,结果是: 错误:使用未声明的标识符"B" 朋友无效 B::hello();

如果我颠倒位置(A <--> B),我有: 错误:使用未声明的标识符"A" std::vector x{A(10)};

有没有正确的方法??

谢谢!


编辑:

谢谢你,克雷格·杨

溶液:

#include <iostream>
#include <string>
#include <vector>
class A;
class B {
private:
std::vector<A> x;
public:
B();
void hello();
};
class A
{
friend void B::hello();
public:
A(int i) : number{i} {}
private:
void f() {
std::cout << "hello" << std::endl;
}
int number;
};
B::B() : x{A(10)}
{
}
void B::hello()
{
for(A &elem : x)
{
elem.f();
}
}
int main()
{

return 0;
}

结论:

  • 这本书是不完整的,因为它没有暴露首先对类A进行前向声明的必要性,以及在这种情况下不可能进行类内初始化。
  • 我没有注意到问题是 A(10),而不是向量!也就是说,当我们将其用作向量的 Template 参数时,我们可以使用不完整的类型 A(仅声明,没有定义)(因为它本身不会创建 A 对象),但在定义对象时我们不能使用不完整的类型 A,例如:A(10);

首先

好吧,您没有正确遵循指南。

首先,定义 Window_mgr 类,该类声明但不能定义 clear。必须先声明 Screen,然后清除才能使用 Screen 的成员。

您必须在A之前声明B

接下来,定义类 Screen,包括用于清除的好友声明。

现在宣布AB::hello()为朋友。

最后,定义 clear,现在可以引用屏幕中的成员。

B:hello()可以使用A的私有成员。

这在前面已经介绍过了: C++ 前向声明,友元函数问题

您添加了并发症

此外,您希望B声明引用A。要实现这一点,您需要转发声明A以便B知道它的存在。

重要的是要 意识到您只有"部分"访问权限A.您不能在B声明中"充分利用"A。所以B中的以下行是错误的。

//You're trying to create A when you only know it exists.
//You don't have a full definition of A yet.
std::vector<A> x{A(10)};
//Replace the above with...
std::vector<A> x;

当然,您必须找到另一种方法来初始化x


示例代码

#include <iostream>
#include <vector>
class A;
class B
{
private:
std::vector<A> x;
public:
void hello();
};
class A
{
friend void B::hello();
public:
A(int i): number(i) {}
private:
void f() { std::cout << "hello" << std::endl; }
int number;
};
void B::hello()
{     
for(A &elem : x)
{
elem.f();
}
}
int main()
{
A a{5};
return 0;
}

你必须有一个更早的声明,而不是一个更早的定义

添加

class A;
class B;

在前面告诉编译器"A"和"B"指的是类。 这应该足以让它推理出其余的。

相关内容

最新更新