Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com
Answertopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions
Privacy Policy

  




 

 

Thinking in C++
Prev Contents / Index Next

Friends

What if you want to explicitly grant access to a function that isn’t a member of the current structure? This is accomplished by declaring that function a friend inside the structure declaration. It’s important that the friend declaration occurs inside the structure declaration because you (and the compiler) must be able to read the structure declaration and see every rule about the size and behavior of that data type. And a very important rule in any relationship is, “Who can access my private implementation?”

The class controls which code has access to its members. There’s no magic way to “break in” from the outside if you aren’t a friend; you can’t declare a new class and say, “Hi, I’m a friend of Bob!” and expect to see the private and protected members of Bob.

You can declare a global function as a friend, and you can also declare a member function of another structure, or even an entire structure, as a friend. Here’s an example :

//: C05:Friend.cpp
// Friend allows special access

// Declaration (incomplete type specification):
struct X;

struct Y {
  void f(X*);
};

struct X { // Definition
private:
  int i;
public:
  void initialize();
  friend void g(X*, int); // Global friend
  friend void Y::f(X*);  // Struct member friend
  friend struct Z; // Entire struct is a friend
  friend void h();
};

void X::initialize() { 
  i = 0; 
}

void g(X* x, int i) { 
  x->i = i; 
}

void Y::f(X* x) { 
  x->i = 47; 
}

struct Z {
private:
  int j;
public:
  void initialize();
  void g(X* x);
};

void Z::initialize() { 
  j = 99;
}

void Z::g(X* x) { 
  x->i += j; 
}

void h() {
  X x;
  x.i = 100; // Direct data manipulation
}

int main() {
  X x;
  Z z;
  z.g(&x);
} ///:~

struct Y has a member function f( ) that will modify an object of type X. This is a bit of a conundrum because the C++ compiler requires you to declare everything before you can refer to it, so struct Y must be declared before its member Y::f(X*) can be declared as a friend in struct X. But for Y::f(X*) to be declared, struct X must be declared first!

Here’s the solution. Notice that Y::f(X*) takes the address of an X object. This is critical because the compiler always knows how to pass an address, which is of a fixed size regardless of the object being passed, even if it doesn’t have full information about the size of the type. If you try to pass the whole object, however, the compiler must see the entire structure definition of X, to know the size and how to pass it, before it allows you to declare a function such as Y::g(X).

By passing the address of an X, the compiler allows you to make an incomplete type specification of X prior to declaring Y::f(X*). This is accomplished in the declaration:

struct X;

This declaration simply tells the compiler there’s a struct by that name, so it’s OK to refer to it as long as you don’t require any more knowledge than the name.

Now, in struct X, the function Y::f(X*) can be declared as a friend with no problem. If you tried to declare it before the compiler had seen the full specification for Y, it would have given you an error. This is a safety feature to ensure consistency and eliminate bugs.

Notice the two other friend functions. The first declares an ordinary global function g( ) as a friend. But g( ) has not been previously declared at the global scope! It turns out that friend can be used this way to simultaneously declare the function and give it friend status. This extends to entire structures:

friend struct Z;

is an incomplete type specification for Z, and it gives the entire structure friend status.

Thinking in C++
Prev Contents / Index Next

 
 
   Reproduced courtesy of Bruce Eckel, MindView, Inc. Design by Interspire