Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specify a class member function as a friend of another class?

Tags:

c++

friend

According to the C++ Primer book, the author mentioned that we can specify a class member function as a friend of another class, instead of the entire class (page 634).

Then, I tested this code:

class A
{
public:
    friend void B::fB(A& a);
    void fA(){}
};
class B
{
public:
    void fB(A& a){};
    void fB2(A& a){};
};

I just wanted the fB() to be friend of class A, not the entire class B. But the above code produced an error: 'B' : is not a class or namespace name. (I am using Visual C++ 2005)

like image 925
ipkiss Avatar asked May 11 '12 06:05

ipkiss


3 Answers

Try putting the B definition before A's:

class A; // forward declaration of A needed by B

class B
{
public:
    // if these require full definition of A, then put body in implementation file
    void fB(A& a); // Note: no body, unlike original.
    void fB2(A& a); // no body.
};

class A
{
public:
    friend void B::fB(A& a);
    void fA(){}
};

A needs the full definition of B. However, B needs to know about A, but does not need the full definition, so you need the forward declaration of A.

like image 106
juanchopanza Avatar answered Nov 14 '22 14:11

juanchopanza


When the compiler starts compiling the code( usually from top ) and it encounters this line:

friend void B::fB(A& a);
  1. at this point, compiler has no idea about type info of B so it throws an error ( 'B' : is not a class or namespace name ).

  2. by forward declaration of class B, compiler knows about type of B is Class in advance to its actual declaration with all members.

  3. run below code after forward declaration of class B.

///////////////

class B;
class A
{
public:
    friend void B::fB(A& a); 
    void fA(){};
};
class B
{
public:
    void fB(A& a){};
    void fB2(A& a){};
};

Still error !!!

because forward declaration is just a declaration of an identifier for which the programmer has not yet given a complete definition. so compiler needs full definition of B before class A.

Note: class A definition dependents on type of B and also definition of B (i.e B::fB) so that forward declaration alone can not resolve, complete definition of class B needs to define before class A.

4 run this code

////////

class B
{
public:
    void fB(A& a){};
    void fB2(A& a){};
};
class A
{
public:
    friend void B::fB(A& a); 
    void fA(){}
};

Still error !!!

because class B member functions fB & fB2 having arguments of type A but compiler has no idea about type info of A so by forward declaration of class A, we can let compiler knows about type info of A. Note: class B definition only dependent on type of A not the members of A so that forward declaration of A resolve step 4.

  1. final code

////////////////////////

class A;  // forward declaration of A needed by B
class B
{
public:
    void fB(A& a);
};

class A
{
    int i;
public:
    friend void fA(A& a);    //specifying function fA as a friend of A, fA is not member function of A
    friend void B::fB(A& a); //specifying B class member function fB as a friend of A
};

// fA is Friend function of A
void fA(A& a)
{
    a.i  = 11; // accessing and modifying Class A private member i
    cout<<a.i<<endl;
}

// B::fB should be defined after class A definition only because this member function can access Class A members
void B::fB(A& a)
{
    a.i  = 22; // accessing and modifying Class A private member i in Class B member function fB
    cout<<a.i<<endl;
}

int main()
{
    A a;
    fA(a);    // calling friend function of class A

    B b;
    b.fB(a);  // calling B class member function fB, B:fB is friend of class A

    return 0;
}

6 Exercise:

// Cyclic dependency 
#include<iostream>
using namespace std;

class A;

class B
{
public:
    void fB(A& a);
    friend void A::fA(B& b); //specifying class A's member function fA as a friend of B
};

class A
{
    int i;
public:
    void fA(B& b);  
    friend void B::fB(A& a); //specifying class B's member function fB as a friend of A
};

int main()
{
    return 0;
}
like image 6
SrinivasPaladugu Avatar answered Nov 14 '22 13:11

SrinivasPaladugu


For this to work, the full definition of B needs to be known before the definition of A.

So forward declare A, since B doesn't need the full type, and switch the definitions around:

class A;
class B
{
public:
    void fB(A& a){};
    void fB2(A& a){};
};
class A
{
public:
    friend void B::fB(A& a);
    void fA(){}
};
like image 3
Luchian Grigore Avatar answered Nov 14 '22 14:11

Luchian Grigore