C++ 作为朋友的成员功能:Lippman 5th这本书错了吗?
利普曼5号 ISBN-13:978-0321714114 第280-281页,上面写着: 让会员成为朋友 Screen可以使整个Window_mgr类成为朋友,而不是成为朋友 而是指定只允许clear成员访问。当我们 声明一个成员函数为友元,我们必须指定 哪个职能部门是成员:C++ 作为朋友的成员功能:Lippman 5th这本书错了吗?,c++,C++,利普曼5号 ISBN-13:978-0321714114 第280-281页,上面写着: 让会员成为朋友 Screen可以使整个Window_mgr类成为朋友,而不是成为朋友 而是指定只允许clear成员访问。当我们 声明一个成员函数为友元,我们必须指定 哪个职能部门是成员: class Screen { // Window_mgr::clear must have been declared before class Screen friend void Window_mgr:
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。必须先声明屏幕,然后clear才能使用 银幕成员
- 接下来,定义类屏幕,包括用于清除的好友声明
- 最后,定义clear,它现在可以引用屏幕中的成员
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, ' ')};
};
类窗口\u管理器{
公众:
//窗口上每个屏幕的位置ID
使用ScreenIndex=std::vector::size\u type;
//在给定位置将屏幕重置为所有空白
空白清除(屏幕索引);
私人:
病媒筛选{Screen(24,80,')};
};
因此,在不定义屏幕的情况下,首先定义窗口管理器是不可能的
以前!
同时,如果没有我们的帮助,就不可能定义屏幕
已定义的窗口管理器
这个问题怎么解决???
这本书错了吗
我将在这里粘贴一个代码,以便您可以使用
最小代码:
#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::你好();
公众:
A(inti):数{i}{}
私人:
void f(){
std::cout您必须有一个更早的声明,但不能有一个更早的定义
添加
class A;
class B;
前面的代码告诉编译器“A”和“B”引用类。这应该足以让它推断出其余的部分。作为开始
嗯,你没有正确地遵循指南
首先,定义Window_mgr类,该类声明但不能定义clear.Screen,在clear可以使用Screen的成员之前,必须声明Screen
您必须在A
之前声明B
接下来,定义类屏幕,包括用于清除的好友声明
现在将A
与B::hello()
声明为朋友
最后,定义clear,它现在可以引用屏幕中的成员
B:hello()
可以使用A
的私有成员
在此之前已经介绍过:
你增加了复杂性
此外,您希望B
的声明引用A
。为此,您需要转发declareA
,以便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;
此解决方案无效:错误:嵌套名称说明符friend void B::hello()中命名的类型“B”不完整;在A/B示例中,除了friendless之外,您还有其他问题,因为您包含了方法体,因此需要实现细节,而不仅仅是类签名。这就是类通常在头文件中定义其签名的原因。如果删除方法体,则数据成员std::vector x{A(10) }来解决。这本书忽略了这个问题。数据成员本身很好,它是一个核心调用,给它一个循环引用的值。把它放在类签名之后提供的ctor体中。我试图在a之前声明B,但我没有注意到问题是a(10),而不是向量!也就是说,我们可以使用不完整的类型a(仅声明,无定义)将其用作向量的模板参数时(因为它本身不创建对象)但是,在定义对象时,我们不能使用不完整的类型A,例如:A u;我将编辑我的问题并接受您的回答。谢谢!当您说我增加了复杂性时,我不同意您的说法。请参阅std::vector screens{Screen(24,80,')}行;也就是说,这本书是不完整的,因为它没有揭示进行A类正向声明的必要性以及在这种情况下不可能进行类内初始化。我的编辑更正了这两个问题。再次感谢。
//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;
#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;
}