C ++ friend classes and friend member functions

I am learning about friend functions, friend classes, and member functions in C ++ classes; Now the following code compiles fine:

#include <iostream>

class A 
{
public:
    friend class B;
    //friend void B::set(int i);
    //friend int B::get();
    friend int function(A a);
    A(int i);
    void set(int i);
    int get();
private:
    int i;
};

A::A(int i) : i(i)
{
}

void A::set(int i)
{
    this->i = i;
}

int A::get()
{
    return i;
}

class B
{
public:
    B(A a);
    void set(int i);
    int get();
private:
    A a;
};

B::B(A a) : a(a)
{
}

void B::set(int i)
{
    a.i = i;
}

int B::get()
{
    return a.i;
}

int function(A a);

int main(int argc, char *argv[])
{
    A a(0);
    std::cout << "in A i=" << a.get() << std::endl;
    a.set(10);
    std::cout << "in A i=" << a.get() << std::endl;
    B b(a);
    std::cout << "in B i=" << b.get() << std::endl;
    b.set(21);
    std::cout << "in B i=" << b.get() << std::endl;
    std::cout << "function returns " << function(a) << std::endl;
}

int function(A a)
{
    return a.i;
}

      

I can provide friendship to class B and function "function" in class A without directly declaring class B or function "function". Now, if I want to provide friendship to two member functions in class B, it doesn't work if I don't define class B before defining class A:

#include <iostream>

class B;   // doesn't work, incomplete type (complete type needed)

class A 
{
public:
    //friend class B;
    friend void B::set(int i);
    friend int B::get();
    friend int function(A a);
    A(int i);
    void set(int i);
    int get();
private:
    int i;
};

A::A(int i) : i(i)
{
}

void A::set(int i)
{
    this->i = i;
}

int A::get()
{
    return i;
}

B::B(A a) : a(a)
{
}

void B::set(int i)
{
    a.i = i;
}

int B::get()
{
    return a.i;
}

int function(A a);

int main(int argc, char *argv[])
{
    A a(0);
    std::cout << "in A i=" << a.get() << std::endl;
    a.set(10);
    std::cout << "in A i=" << a.get() << std::endl;
    B b(a);
    std::cout << "in B i=" << b.get() << std::endl;
    b.set(21);
    std::cout << "in B i=" << b.get() << std::endl;
    std::cout << "function returns " << function(a) << std::endl;
}

int function(A a)
{
    return a.i;
}

      

but I cannot define class B before defining class A, so I am stuck. Forward declaration (not defining) of class B also doesn't work.

So my questions are:

1) why don't I need to forward a function or whole class declaration in a friendship declaration, but I need to define a class if I need to specify the member functions of that class? I know friendship declarations are not common sense declarations (they just grant access, they don't advertise anything).

2) how can I compile my code (besides declaring the member object A in B as A * a)?

+3


source to share


2 answers


Here is an example of a friend class and how to use it. This was done by cplusplus.com The reason I am posting this is because your example does not really illustrate the correct use of friendship in C ++. I hope this clears up the question of how / why you should use friendship, and it may lead to a solution to your problems with a future declaration.

// friend class
#include <iostream>
using namespace std;

class Square;

class Rectangle {
    int width, height;
  public:
    int area ()
      {return (width * height);}
    void convert (Square a);
};

class Square {
  friend class Rectangle;
  private:
    int side;
  public:
    Square (int a) : side(a) {}
};

void Rectangle::convert (Square a) {
  width = a.side;
  height = a.side;
}

int main () {
  Rectangle rect;
  Square sqr (4);
  rect.convert(sqr);
  cout << rect.area();
  return 0;
}

      



In this example, the Rectangle class is a friend of the Square class that allows Rectangle member functions to access private and protected square members. More specifically, Rectangle accesses a member variable Square :: side that describes the side of the square.

This example has something new: at the beginning of the program, there is an empty declaration for the Square class. This is necessary because the Rectangle class uses Square (converts to a member as a parameter), and Square uses Rectangle (declares it a friend).

Friendships never match unless specified: In our example, Rectangle is considered a friend by area class, but Square is not considered a friend of Rectangle. Therefore, member functions of the Rectangle can access the protected and private members of Square, but not vice versa. Of course, the area can also be declared as a friend of the Rectangle, if necessary, providing such access.

Another property of friendship is that they are not transitive: Each other is not considered a friend unless explicitly stated.

+1


source


Just make a class B

friend class A

. There are no side effects for this.

If you are absolutely sure you want to use finer control, you can do it with a proxy class like this (using your bare bones split example):



class Proxy;

class A
{
public:
    friend class Proxy;
    A(int i);
private:
    int i;
};

class B
{
public:
    B(A a);
    void set(int i);
    int get();
private:
    A a;
};

class Proxy
{
  friend void B::set(int);
  friend int B::get();
  static int& get_i(A& a) { return a.i; }
  static const int& get_i(const A& a) { return a.i; }
};

      

Now you can use Proxy::get_i(a)

instead of a.i

in B::set

and B::get

(only).

0


source







All Articles