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,包括用于清除的好友声明。
现在宣布A
与B::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"指的是类。 这应该足以让它推理出其余的。