简体   繁体   English

朋友类或朋友成员函数 - 前向声明和头部包含

[英]Friend Class or Friend member function - Forward declaration and Header inclusion

Yeah the question topic has been discussed so many times. 是的,问题主题已被讨论了很多次。 And I'm almost clear about the difference. 而且我几乎清楚这种差异。 I've just one doubt related to an example in the book. 我只是怀疑与书中的一个例子有关。

This question is related to my previous question , where I presented 2 classes taken as example in the book C++ Primer. 这个问题与我之前的问题有关, 在C ++ Primer一书中提到了2个类。

In reference to those classes, the book quotes the following paragraph, specially related to the declaration of member function of WindowManager class as friend function. 在引用这些类时,本书引用了以下段落,特别是与WindowManager类的成员函数声明作为友元函数有关。 Here's what it says: 这就是它所说的:

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 cannot define, clear. 首先,定义Window_mgr类,它声明但无法定义,清除。 Screen must be declared before clear can use the members of Screen. 必须在clear之前声明屏幕才能使用Screen的成员。
  • Next, define class Screen, including a friend declaration for clear. 接下来,定义类Screen,包括clear的友元声明。
  • Finally, define clear, which can now refer to the members in Screen. 最后,定义clear,现在可以引用Screen中的成员。

The code I presented in that question follows this structure only. 我在该问题中提出的代码仅遵循此结构。 But it seems that it is not working out. 但它似乎没有成功。 This makes me think if the above points are misguiding or I didn't implement it correctly. 这让我想到如果以上几点是误导或我没有正确实现它。

The problem is, when I declare the clear function as friend function in ScreenCls class, I fall into cyclic inclusion of header files. 问题是,当我在ScreenCls类中声明clear函数作为友元函数时,我会陷入头文件的循环包含 I'll brief out the specific part of both classes here again: 我将再次在这里简要介绍这两个类的具体部分:

ScreenCls.h: 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
}

Here I've to include the WindowManager.h header file, as clear function is now using the ScreenIndex defined there. 这里我要包含WindowManager.h头文件,因为clear函数现在使用ScreenIndex定义的ScreenIndex Forward Declaration won't work here (Correct me if I'm wrong). 转发声明在这里不起作用(如果我错了,请纠正我)。

Now, next we move on to WindowManager.h : 现在,接下来我们转到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, ' ') };
};

And concentrate onto the declaration of screens here. 并专注于这里的screens宣言。 They have used list initializer to add a default ScreenCls to the vector . 他们使用列表初始化程序将默认的ScreenCls添加到vector So, here again we need to include the WindowManager.h . 所以,我们再次需要包含WindowManager.h And now we are into cyclic inclusion. 现在我们进入循环包容。 This prevents my project from building. 这可以防止我的项目建立。

However, if I change the friend function declaration to make the entire class as friend, then I can work with forward declaring the WindowManager class. 但是,如果我更改友元函数声明以使整个类成为朋友,那么我可以使用forward declaring WindowManager类。 In that case, it will work fine. 在这种情况下,它会正常工作。

So, basically friend function isn't working here, but friend class is working. 所以,基本上朋友功能在这里不起作用,但朋友班正在工作。 So, is it that the above points are not going well with their implementation, or there's something wrong with my classes? 那么,以上几点对于它们的实现是不是很顺利,或者我的课程出了什么问题? I just want to know this to clearly understand the concept of header inclusion and forward declaration . 我只是想知道这一点,以清楚地理解header inclusionforward declaration的概念。

The questions linked in my previous question describe that well. 我之前的问题中提到的问题很好地描述了这一点。 But it's just that it's not working in the above situation, so I'm asking it again. 但这只是因为它不能在上述情况下工作,所以我再次问它。

I guess your problem is with the screen initializer. 我想你的问题在于屏幕初始化程序。 You cannot initialize any data in *.h files that are inside a class. 您无法初始化类中的* .h文件中的任何数据。 So, I suggest you to do something like that: 所以,我建议你做那样的事情:

#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
};

As long as you are not using the class, ie calling a method on an object or calling new for instance or reserving an Array of instances of the class you can go with forward declarations only. 只要您没有使用该类,即调用对象上的方法或调用new实例或保留类的实例数组,您只能使用前向声明。 As a rule of tumb: if the compiler does not complain when you use forward declarations, use them and avoid includes which slow down compilation. 作为tumb的规则:如果编译器在使用前向声明时没有抱怨,请使用它们并避免包含哪些减慢编译速度。

Only danger: when you cast with multiple inheritance and don't have the include, the cast will not work well - but this usually you would do in the .cpp where you should include classes you use. 只有危险:当你使用多重继承并且没有包含时,强制转换将无法正常工作 - 但通常你会在.cpp中进行,你应该包含你使用的类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM