Rohit Jain
Rohit Jain

Reputation: 213311

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.

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. 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. Screen must be declared before clear can use the members of Screen.
  • Next, define class Screen, including a friend declaration for clear.
  • Finally, define clear, which can now refer to the members in 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. I'll brief out the specific part of both classes here again:

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. Forward Declaration won't work here (Correct me if I'm wrong).

Now, next we move on to 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. They have used list initializer to add a default ScreenCls to the vector. So, here again we need to include the 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. 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.

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.

Upvotes: 4

Views: 915

Answers (2)

Amadeus
Amadeus

Reputation: 10665

I guess your problem is with the screen initializer. You cannot initialize any data in *.h files that are inside a class. 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
};

Upvotes: 2

Waltika
Waltika

Reputation: 27

As long as you are not using the class, i.e. 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. 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.

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.

Upvotes: 1

Related Questions