4

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.

Community
  • 1
  • 1
Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
  • I think you mean "*ScreenCls.h*" here: "So, here again we need to include the *WindowManager.h*" – psibar May 14 '13 at 19:50
  • @psibar. I don't think we can do something like that. `ScreenIndex` is a type alias defined in WindowManager class. We can only forward declare a class or function (from what I've read till now). – Rohit Jain May 14 '13 at 20:06
  • I come across the same problem. I think the solution provided in the book is wrong. We just cannot do that. – delphifirst Dec 21 '14 at 03:35

2 Answers2

2

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
};
Amadeus
  • 10,199
  • 3
  • 25
  • 31
1

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.

Waltika
  • 27
  • 3
  • Yeah that's fine. But what I want to know is as ScreenCls stands as of now, the `clear` function declaration requires that `WindowManager` be included rather than forward declared right? In that case, there is a cyclic dependency. But, if we go with `friend class WindowManager;` instead of the current friend member function declaration, then forward declaration will be ok. Right? – Rohit Jain May 14 '13 at 19:48
  • It would need to be checked but I would say no. When you write this friend, you are just declaring that in the class WindowManager, if there is a method clear it will be able to call private or protected methods. – Waltika Oct 30 '13 at 16:49