4

是的,这个问题已经讨论了很多次了。我几乎很清楚其中的区别。我对书中的一个例子有一个疑问。

这个问题与我之前的问题有关,我在 C++ Primer 一书中提出了 2 个类作为示例。

关于这些类,本书引用了以下段落,特别涉及将WindowManager类的成员函数声明为友元函数。它是这样说的:

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

  • 首先,定义 Window_mgr 类,该类声明但不能定义 clear。必须先声明 Screen,clear 才能使用 Screen 的成员。
  • 接下来,定义类 Screen,包括一个用于 clear 的友元声明。
  • 最后定义clear,现在可以引用Screen中的成员了。

我在该问题中提供的代码仅遵循此结构。但它似乎没有成功。这让我想到上述几点是否有误导性,或者我没有正确实施。

问题是,当我clear在类中将函数声明为友元函数时ScreenCls,我陷入了头文件的循环包含。我将在这里再次简要介绍这两个类的具体部分:

ScreenCls.h:

#ifndef SCREENCLS_H
#define SCREENCLS_H

#include <iostream>

#include "WindowManager.h"

using namespace std;

class ScreenCls {
    friend void WindowManager::clear(ScreenIndex);

    // Some other code
}

在这里我必须包含WindowManager.h头文件,因为clear函数现在使用ScreenIndex那里定义的。前向声明在这里不起作用(如果我错了,请纠正我)。

现在,接下来我们继续WindowManager.h

#ifndef WINDOWMANAGER_H
#define WINDOWMANAGER_H

#include <iostream>
#include <vector>
#include "ScreenCls.h"

using namespace std;

class WindowManager {
public:
    // location ID for each screen on window
    using ScreenIndex = vector<ScreenCls>::size_type;

private:
    vector<ScreenCls> screens{ ScreenCls(24, 80, ' ') };
};

并专注于screens这里的声明。他们使用列表初始值设定项ScreenClsvector. 所以,这里我们需要再次包含WindowManager.h. 现在我们进入了循环包容。这会阻止我的项目构建。

但是,如果我更改友元函数声明以使整个类成为友元,那么我可以使用forward declaring该类WindowManager。在这种情况下,它会正常工作。

所以,基本上朋友功能在这里不起作用,但朋友类正在工作。那么,是上述几点在实施方面进展不顺利,还是我的课程有问题?我只是想知道这一点以清楚地理解header inclusionand的概念forward declaration

我上一个问题中链接的问题很好地描述了这一点。但只是在上述情况下它不起作用,所以我再次问它。

4

2 回答 2

2

我猜你的问题出在屏幕初始化程序上。您不能初始化类内 *.h 文件中的任何数据。所以,我建议你做这样的事情:

#ifndef WINDOWMANAGER_H
#define WINDOWMANAGER_H

#include <iostream>
#include <vector>
//#include "ScreenCls.h"

using namespace std;
class ScreenCls;

class WindowManager {
public:
    // location ID for each screen on window
    using ScreenIndex = vector<ScreenCls>::size_type;

private:
    vector<ScreenCls> screens; //{ ScreenCls(24, 80, ' ') };    remove this
};
于 2013-05-14T20:13:24.757 回答
1

只要您不使用该类,即调用对象上的方法或调用 new 例如或保留类的实例数组,您就可以只使用前向声明。作为一条规则:如果编译器在您使用前向声明时没有抱怨,请使用它们并避免包含减慢编译的包含。

唯一的危险:当您使用多重继承进行转换并且没有包含时,转换将无法正常工作 - 但这通常您会在 .cpp 中执行,您应该在其中包含您使用的类。

于 2013-05-14T19:43:32.037 回答