본문 바로가기

IT

Friend functions and classes

socure: C++ for dummies by Stephen Randy Davis

Occasionally, you want a non-member function to have access to the protected
members of a class. You do so by declaring the function to be a friend of the class by using the keyword friend. Sometimes, an external function can use direct access to a data member. I know this appears to break the strictly defined, well-sealed-off class interface position that I’ve been advocating, but just consider the following. First,
including a friend function is, in effect, adding that function to the interface (that’s why a class shouldn’t have too many friends). You’re okay as long as you attempt to treat this function as a normal function that, oh yeah, happens to have direct access. Second, providing a public access method that acts as a thin veil over a data member doesn’t do anything to abstract away class details. Such a thin veneer function fulfills the letter of the law, but not the spirit.

The friend declaration appears in the class that contains the protected member. The friend declaration is like a prototype declaration in that it includes the extended name and the return type. In the following example, the function initialize() can now access anything it wants in Student:

class Student
{
friend void initialize(Student*);
public:
// same public members as before...
protected:
int semesterHours; // hours earned toward graduation
float gpa;
};
// the following function is a friend of Student
// so it can access the protected members
void initialize(Student *pS)
{
pS->gpa = 0; // this is now legal...
pS->semesterHours = 0; // ...when it wasn’t before
}

A single function can be declared a friend of two classes at the same time. Although this can be convenient, it tends to bind the two classes together. This binding of classes is normally considered bad because it makes one class dependent on the other. If the two classes naturally belong together, however, it’s not all bad, as shown here:

class Student; // forward declaration
class Teacher
{
friend void registration(Teacher& t, Student& s);
public:
void assignGrades();
protected:
int noStudents;
Student *pList[100];
};
class Student
{
friend void registration(Teacher& t, Student& s);
public:
// same public members as before...
protected:
Teacher *pT;
int semesterHours; // hours earned toward graduation
float gpa;
};

void registration(Teacher& t, Student& s)
{
// initialize the Student object
s.semesterHours = 0;
s.gpa = 0;
// if there’s room...
if (t.noStudents < 100)
{
// ...add it onto the end of the list
t.pList[t.noStudents] = &s;
t.noStudents++;
}
}

In this example, the registration() function can reach into both the Student and Teacher classes to tie them together at registration time, without being a member function of either one. The first line in the example declares the class Student, but none of its members. This is called a forward declaration and just defines the name of the
class so that other classes, such as Teacher, can define a pointer to it. Forward references are necessary when two classes refer to each other. A member function of one class may be declared a friend of another class, as shown here:

class Teacher
{
// ...other members as well...
public:
void assignGrades();
};
class Student
{
friend void Teacher::assignGrades();
public:
// same public members as before...
protected:
int semesterHours; // hours earned toward graduation
float gpa;
};
void Teacher::assignGrades()
{
// can access protected members of Teacher from here
}
Unlike in the non-member example, the member function assignGrades()
must be declared before the class Student can declare it to be a friend.

An entire class can be named a friend of another. This has the effect of
making every member function of the class a friend
:

class Student; // forward declaration
class Teacher
{
protected:
int noStudents;
Student *pList[100];
public:
void assignGrades();
};
class Student
{
friend class Teacher; // make entire class a friend
public:
// same public members as before...
protected:
int semesterHours; // hours earned toward graduation
float gpa;
};
Now, any member function of Teacher has access to the protected members
of Student. Declaring one class a friend of the other inseparably binds the
two classes together.