class Example{
public:
friend void Clone::f(Example);
Example(){
x = 10;
}
private:
int x;
};
class Clone{
public:
void f(Example ex){
std::cout << ex.x;
}
};
When I write f as a normal function, the program compiles successful. However, when I write f as a class member, this error occurs.
Screenshot:
The error you're seeing is not a root-cause compilation error. It is an artifact of a different problem. You're friending to a member function of a class the compiler has no earthly clue even exists yet,much less exists with that specific member.
A friend declaration of a non-member function has the advantage where it also acts as a prototype declaration. Such is not the case for a member function. The compiler must know that (a) the class exists, and (b) the member exists.
Compiling your original code (I use clang++ v3.6), the following errors are actually reported:
main.cpp:6:17: Use of undeclared identifier 'Clone'
main.cpp:17:25: 'x' is a private member of 'Example'
The former is a direct cause of the latter. But doing this instead:
#include <iostream>
#include <string>
class Example;
class Clone
{
public:
void f(Example);
};
class Example
{
public:
friend void Clone::f(Example);
Example()
{
x = 10;
}
private:
int x;
};
void Clone::f(Example ex)
{
std::cout << ex.x;
};
int main()
{
Clone c;
Example e;
c.f(e);
}
Output
10
This does the following:
Forward declares Example
Declares Clone, but does not implement Clone::f (yet)
Declares Example, thereby making x known to the compiler.
Friends Clone::f to Example
Implements Clone::f
At each stage we provide what the compiler needs to continue on.
Best of luck.
Related
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);
For a start
Well, you're not following the guidance correctly.
First, define the Window_mgr class, which declares, but cannot define, clear. Screen must be declared before clear can use the members of Screen.
You must declare B before A.
Next, define class Screen, including a friend declaration for clear.
Now declare A with B::hello() as a friend.
Finally, define clear, which can now refer to the members in Screen.
B:hello() can use the private members of A.
This has been covered before here: C++ Forward declaration , friend function problem
You've added complications
Furthermore you want declarations of B to reference A. To achieve this you need to forward declare A so that B knows of its existence.
And it's important to be aware that you have only "partial" access to A. You cannot 'fully use' A in the declaration of B. So the following line in B is wrong.
//You're trying to create A when you only know it exists.
//You don't have a full definition of A yet.
std::vector<A> x{A(10)};
//Replace the above with...
std::vector<A> x;
Of course you'll have to find another way to initialise x.
Sample code
#include <iostream>
#include <vector>
class A;
class B
{
private:
std::vector<A> x;
public:
void hello();
};
class A
{
friend void B::hello();
public:
A(int i): number(i) {}
private:
void f() { std::cout << "hello" << std::endl; }
int number;
};
void B::hello()
{
for(A &elem : x)
{
elem.f();
}
}
int main()
{
A a{5};
return 0;
}
You have to have an earlier declaration, but not an earlier definition.
Adding
class A;
class B;
at the front tells the compiler that “A” and “B” refer to classes. That should be enough for it to reason out the rest.
I have two classes, Friend2 is a friend of Friend1. After Friend2 accesses the Friend1's private member variable, I want Friend1 to be able to access the Friend2's public member functions. So I decided to use composition inside Friend1. However, the compiler shows me the error:
use of undefined type 'friend2'
Then, I tried another way, making Friend1 a friend of Friend2 too. But I still got the same error. Would anyone teach me the way to solve? Thx a lot!
#ifndef FRIEND1_H
#define FRIEND1_H
class friend2;
class friend1 {
private:
int x;
public:
friend1();
int comp(friend2* f2o);
friend class friend2;
};
friend1::friend1() {
x = 1;
}
int friend1::comp(friend2* f2o) {
return f2o->getxx(); //the error : use of undefined type
}
#endif
#ifndef FRIEND2_H
#define FRIEND2_H
#include "friend1.h"
#include <iostream>
class friend2 {
private:
int xx;
public:
friend2();
void p(friend1* f1o);
int getxx() const;
friend class friend1;
};
friend2::friend2() {}
void friend2::p(friend1* f1o) {
xx = f1o->x;
}
int friend2::getxx() const {
return xx;
}
#endif
Also, is composition or friend class the better way to do this? Why?
You get //the error : use of undefined type because class Friend2 is only declared, not defined at that point. To solve this move int friend1::comp(friend2* f2o) implementation to friend1.cpp and include friend2.h from there.
UPDATE In general, if two classes are mutual friends (and even if only one of them is a friend to another), it's a good reason to think about the design.
I am actually testing a file and I have a situation, where I need to access some of the protected members of the class from main.cpp. I tried to add, main() as friend, didn't work out and learned that it wont work, so I moved everything in the main() to a test () and made the test() as friend. still it shows the error.
Example would be
//--File.hpp
namespace Files {
class File {
public:
File(long word_):word(word_) {}
protected:
long word;
private:
friend int test();
};
}//ns:Files
//--List_File.hpp
namespace Files {
class List_File :public File {
public:
List_File() : File(sizeof(int) + sizeof(long)) {}
private:
friend int test();
};
}//ns:Files
//--main.cpp
using namespace Files;
int test() {
File *pd = new List_File();
assert(pd->word == 12); //LINE 34
return 0;
}
int main() {
test();
return 0;
}
//it says error on Line 34: Base::value is protected. Please advice.
g++ -O -Wall -Wno-unused -o a.out File.cpp List_File.cpp Data_File.cpp
Free_List_File.cpp main.cpp
File.hpp: In function ‘int test()’:
File.hpp:30:7: error: ‘long int Files::File::word’ is protected
main.cpp:34:16: error: within this context
make: *** [a.out] Error 1
No, it definitely doesn't have to be in the same file, but it obviously has to "know" what the class is, i.e.: the header that has the class definition should be included in the file where the function is implemented. Your code should be fine, as commented.
after you added some context
Your test function is not in the Files namespace. If you want it to be in the global context, you should treat it as "::test" within the namespace, otherwise the compiler might expect the "Files::test" to be the friend function, and not the "::test" as in your case. Can't find the formal standard reference, but I'm pretty sure that's the case. Note that you're performing a forward declaration here, so there's no default fall-back to the upper level of scope for name resolution.
Maybe you missing inheritance declaration in Derived class?
class Derived : public Base {
I've tested your code (with inheritance declaration included) and it produced no error
littedev is right!!
Updated the code according to the comments by littedev..
//--File.hpp
namespace Files {
class File {
public:
File(long word_):word(word_) {}
protected:
long word;
private:
friend int test();
};
}//ns:Files
//--List_File.hpp
namespace Files {
class List_File :public File {
public:
List_File() : File(sizeof(int) + sizeof(long)) {} \
private:
friend int test();
};
}//ns:Files
//--main.cpp
namespace Files{
int test() {
File *pd = new List_File();
assert(pd->word == 12); //LINE 34
return 0;
}
int main() {
Files::test();
return 0;
}
}
I would guess that you are trying to access a protected variable outside of the scope of the Files class definition. I would recommend a function that returns the variable word when it is called and use that instead of trying to access a protected variable outside of a class definition. I could be wrong in that I am not really sure what is the scope of a protected variable (whether it is limited only to class declarations or whether it can be accessed outside of the class definition) but I am pretty sure that I am right because protected variables are like private variables. They are only accessible within the class scope. Correct me if I am wrong.
EDIT: Oh I am sorry I didn't realize what you were doing. littleadv is right, your function declaration isn't within the files namespace.
I am reading "Local Classes" concept in Object-oriented programming with C++ By Balagurusamy (http://highered.mcgraw-hill.com/sites/0070593620/information_center_view0/).
The last line says "Enclosing function cannot access the private members of a local class. However, we can achieve this by declaring the enclosing function as a friend."
Now I am wondering how the highlighted part can be done?
Here is the code I was trying but no luck,
#include<iostream>
using namespace std;
class abc;
int pqr(abc t)
{
class abc
{
int x;
public:
int xyz()
{
return x=4;
}
friend int pqr(abc);
};
t.xyz();
return t.x;
}
int main()
{
abc t;
cout<<"Return "<<pqr(t)<<endl;
}
I know the code looks erroneous, any help would be appreciable.
Your friend statement is fine.
int pqr() {
class abc {
int x;
public:
abc() : x(4) { }
friend int pqr();
};
return abc().x;
}
int main() {
cout << "Return " << pqr() << endl;
}
Edit:
IBM offers this explanation for the issue raised in the comments:
If you declare a friend in a local class, and the friend's name is unqualified, the compiler will look for the name only within the innermost enclosing nonclass scope. [...] You do not have to do so with classes.
void a();
void f() {
class A {
// error: friend declaration 'void a()' in local class without prior decl...
friend void a();
};
}
friend void a(): This statement does not consider function a() declared in namespace scope. Since function a() has not been declared in the scope of f(), the compiler would not allow this statement.
Source: IBM - Friend scope (C++ only)
So, you're out of luck. Balagurusamy's tip only works for MSVC and similar compilers. You could try handing off execution to a static method inside your local class as a work-around:
int pqr() {
class abc {
int x;
public:
abc() : x(4) { }
static int pqr() {
return abc().x;
}
};
return abc::pqr();
}
There seems to be a misunderstand about local classes.
Normally there are here to help you within the function... and should NOT escape the function's scope.
Therefore, it is not possible for a function to take as an argument its own local class, the class simply isn't visible from the outside.
Also note that a variety of compilers do not (unfortunately) support these local classes as template parameters (gcc 3.4 for example), which actually prevents their use as predicates in STL algorithms.
Example of use:
int pqr()
{
class foo
{
friend int pqr();
int x;
foo(): x() {}
};
return foo().x;
}
I must admit though that I don't use this much, given the restricted scope I usually use struct instead of class, which means that I don't have to worry about friending ;)
I have no solution for the friend thing yet (don't even know if it can be done), but read this and this to find out some more about local classes. This will tell you that you cannot use local classes outside the function they are defined in (as #In silico points out in his answer.)
EDIT It doesn't seem possible, as this article explains:
The name of a function first introduced in a friend declaration is in the scope of the first nonclass scope that contains the enclosing class.
In other words, local classes can only befriend a function if it was declared within their enclosing function.
The friend int pqr(abc); declaration is fine. It doesn't work because the abc type has not been defined before you used it as a parameter type in the pqr() function. Define it before the function:
#include<iostream>
// By the way, "using namespace std" can cause ambiguities.
// See http://www.parashift.com/c++-faq-lite/coding-standards.html#faq-27.5
using namespace std;
// Class defined outside the pqr() function.
class abc
{
int x;
public:
int xyz()
{
return x=4;
}
friend int pqr(abc);
};
// At this point, the compiler knows what abc is.
int pqr(abc t)
{
t.xyz();
return t.x;
}
int main()
{
abc t;
cout<<"Return "<<pqr(t)<<endl;
}
I know you want to use a local class, but what you have set up will not work. Local classes is visible only inside the function it is defined in. If you want to use an instance of abc outside the pqr() function, you have to define the abc class outside the function.
However, if you know that the abc class will be used only within the pqr() function, then a local class can be used. But you do need to fix the friend declaration a little bit in this case.
#include<iostream>
// By the way, "using namespace std" can cause ambiguities.
// See http://www.parashift.com/c++-faq-lite/coding-standards.html#faq-27.5
using namespace std;
// pqr() function defined at global scope
int pqr()
{
// This class visible only within the pqr() function,
// because it is a local class.
class abc
{
int x;
public:
int xyz()
{
return x=4;
}
// Refer to the pqr() function defined at global scope
friend int ::pqr(); // <-- Note :: operator
} t;
t.xyz();
return t.x;
}
int main()
{
cout<<"Return "<<pqr()<<endl;
}
This compiles without warnings on Visual C++ (version 15.00.30729.01 of the compiler).
I am trying to declare and use a class B inside of a class A
and define B outside A.
I know for a fact that this is possible because Bjarne Stroustrup
uses this in his book "The C++ programming language"
(page 293,for example the String and Srep classes).
So this is my minimal piece of code that causes problems
class A{
struct B; // forward declaration
B* c;
A() { c->i; }
};
struct A::B {
/*
* we define struct B like this becuase it
* was first declared in the namespace A
*/
int i;
};
int main() {
}
This code gives the following compilation errors in g++ :
tst.cpp: In constructor ‘A::A()’:
tst.cpp:5: error: invalid use of undefined type ‘struct A::B’
tst.cpp:3: error: forward declaration of ‘struct A::B’
I tried to look at the C++ Faq and the closeset I got was here and here but
those don't apply to my situation.
I also read this from here but it's not solving my problem.
Both gcc and MSVC 2005 give compiler errors on this
The expression c->i dereferences the pointer to struct A::B so a full definition must be visible at this point in the program.
The simplest fix is to make the constructor of A non-inline and provide a body for it after the defintion of struct A::B.
Define the constructor for A AFTER the definition of struct B.
This is a good example of why you want to keep definitions separate from declarations. You need to change the order of things so that the constructor A::A() is defined after the definition of struct A::B.
class A
{
struct B;
B* c;
A();
};
struct A::B
{
int i;
};
A::A() { c->i; }
int main()
{
return 0;
}
Interestingly, I've bumped into the same problem with the page 293 ('11.12 A String Class') mentioned in the Stroustrup book.
The example provided in the printed book seems to be at fault, providing the following methods as inline, instead of defining them after the definition of struct Srep
class String {
// ...
void check(int i) const { if (i<0 || rep->sz <=i) throw Range(); }
char read(int i) const { return rep->s[i]; }
void write(int i, char c) { rep=rep->get_own_copy(); rep->s[i]=c; }
...etc...
I googled a bit, and found the author's latest implementation of this String Class, available here:
http://www2.research.att.com/~bs/string_example.c
He seems to have modified it so that these methods are no longer inline, to avoid the problem mentioned in this thread.