Lippman 5th ISBN-13: 978-0321714114
Page 280-281, it says:
Making A Member Function a Friend
Rather than making the entire Window_mgr class a friend, Screen can instead specify that only the clear member is allowed access. When we declare a member function to be a friend, we must specify the class of which that function is a member:
class Screen { // Window_mgr::clear must have been declared before class Screen friend void Window_mgr::clear(ScreenIndex); // ... rest of the Screen class };
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 problem is: class Window_mgr has a data member that depends of class Screen definition. See:
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, ' ')};
};
So it is impossible firstly define Window_mgr without defining Screen previously! And at the same time, it is impossible define Screen without we have defined Window_mgr!!!
How can this problem be solved??? Is the book wrong?
I will paste here a code so that you can repeat the problem using a minimal code:
#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;
}
If I compile this code, the result is: error: use of undeclared identifier 'B' friend void B::hello();
And if I invert the position (A <--> B), I have: error: use of undeclared identifier 'A' std::vector x{A(10)};
Is there a correct way to do that??
Thank you!
EDIT:
Thank you, Craig Young
Solution:
#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;
}
Conclusion:
- the book is incomplete in that it doesn't expose the necessity of doing the forward declaration of class A firstly and the impossibility to do in-class initialization in this case.
- I didn't notice that the problem was the A(10), not the vector! That is, we can use incomplete type A (only declaration, without definition) when we are using it as Template argument to vector (because it doesn't create A object itself) but we can not use incomplete type A when defining a object, for example: A(10);