25

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)

Vishnu CS
  • 748
  • 1
  • 10
  • 24
ipkiss
  • 13,311
  • 33
  • 88
  • 123

8 Answers8

28

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.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • But if in fB(A& a) I use a to access variable in A for instance, a.variable; that would be illegal because A had no been defined yet. – ipkiss May 11 '12 at 07:27
  • 1
    @ipkiss yes, because then you would need the full definition if you that in the header class declaration. But if you did it in a separate implementation file, you could include the full declaration of A. – juanchopanza May 11 '12 at 07:30
7

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;
}
  • @BrunoMartinez - There is no perfect solution to this because both are cyclically dependent on each other's complete definition. My intention of giving this special case was to highlight the importance of decoupling entities in software design and to get more clarity on Friend function while working on this. I guess, you might already aware that the possible option for this is creating a common friend function – SrinivasPaladugu Jan 02 '17 at 10:57
3

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(){}
};
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
2

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

friend void B::fB(A& a);

Then compiler doesn't understand what do you mean by this B::. Even if you have defined this class later in the code but compiler doesn't know that. So it's usually a good to practice to do forward declaration of class( class Name; ) if the definition resides later in the code.

abhimanyuaryan
  • 3,882
  • 5
  • 41
  • 83
0

firstly forward declare class A, so that its visible in class B definition. then define class A containing a friend function from class B.

0

First of all before using a particular class name you will have to declare it first. So you will need a forward declaration of the Class B as you are using it in Class A before the Class B has been originally declared.

Secondly you will need to define the functions (that are using variables from both the classes- here the friend functions ) after both the classes have been defined. Or else we may face errors.

For example

#include<iostream>

using namespace std;

class alpha1;

class alpha2
{
    public:

        void put_bata(int a,int b);
};

void alpha2 :: put_bata(int a,int b)
{
    alpha1 net;

    net.roll=a;

    net.id=b;

    net.get_data();
}

class alpha1
{
    int roll;

    int id;

    public:

        void get_data(void)
        {
            cout<<roll<<endl<<id<<endl;
        }

        friend void alpha2 :: put_bata(int a,int b);
};

int main()
{
    alpha2 gamma;

    gamma.put_bata(5,6);

    return 0;
}

Will show us errors as put_bata tries to access roll and id before they are defined even if we had a forward declaration of the class but the code given below will just work fine.

#include<iostream>

using namespace std;

class alpha1;

class alpha2
{
    public:

        void put_bata(int a,int b);
};

class alpha1
{
    int roll;

    int id;

    public:

        void get_data(void)
        {
            cout<<roll<<endl<<id<<endl;
        }

        friend void alpha2 :: put_bata(int a,int b);
};

void alpha2 :: put_bata(int a,int b)
{
    alpha1 net;

    net.roll=a;

    net.id=b;

    net.get_data();
}


int main()
{
    alpha2 gamma;

    gamma.put_bata(5,6);

    return 0;
}
New_Bee
  • 81
  • 4
0

@juanchopanza @ipkiss Regarding the problem that you can't access data members of A inside fB(A& a) because A is not defined yet. Instead of defining it in a separate file and including it, you can just define the function fB(A& a) after the definition of class A so that fB(A& a) is able to see data members of A.

mrboieng
  • 316
  • 1
  • 9
0
#include <iostream>
#include <string>
using namespace std;
 
class Manager;
class Employee;
 
class Admin{
    public:
    void EmployeeDetails(Employee &obj);
    void ManagerDetails(Manager &obj);
};
 
class Employee{
    string name = "praful";
    friend void Admin::EmployeeDetails(Employee &obj);    
};
 
class Manager{
    string name = "Robert";
    friend void Admin::ManagerDetails(Manager &obj);
};
 
 
void Admin::EmployeeDetails(Employee &obj)
{
    cout << "Employee :" << obj.name << endl;
}
void Admin::ManagerDetails(Manager &obj)
{
    cout << "Manager :" << obj.name << endl;        
}
 
int main()
{
    Employee e;
    Manager m;
    Admin a;
    a.EmployeeDetails(e);
    a.ManagerDetails(m);
    return 0;
}
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 15 '22 at 16:15