Friend Functions. McGraw-Hill The Complete Reference Fourth Edition
Anuncio
Anuncio
C h a p t e r 1 2 : C l a s s e s a n d O b j e c t s
297
Instead, an anonymous union tells the compiler that its member variables are to share the same location. However, the variables themselves are referred to directly, without the normal dot operator syntax. For example, consider this program:
#include <iostream>
#include <cstring> using namespace std; int main()
{
// define anonymous union union { long l; double d; char s[4];
} ;
// now, reference union elements directly l = 100000; cout << l << " "; d = 123.2342; cout << d << " "; strcpy(s, "hi"); cout << s;
} return 0;
As you can see, the elements of the union are referenced as if they had been declared as normal local variables. In fact, relative to your program, that is exactly how you will use them. Further, even though they are defined within a union declaration, they are at the same scope level as any other local variable within the same block. This implies that the names of the members of an anonymous union must not conflict with other identifiers known within the same scope.
All restrictions involving unions apply to anonymous ones, with these additions.
First, the only elements contained within an anonymous union must be data. No member functions are allowed. Anonymous unions cannot contain private or
protected
elements. Finally, global anonymous unions must be specified as static.
Friend Functions
It is possible to grant a nonmember function access to the private members of a class by using a friend. A friend function has access to all private and protected members
298
C + + : T h e C o m p l e t e R e f e r e n c e of the class for which it is a friend. To declare a friend function, include its prototype within the class, preceding it with the keyword friend. Consider this program:
#include <iostream> using namespace std; class myclass { int a, b; public: friend int sum(myclass x);
}; void set_ab(int i, int j); void myclass::set_ab(int i, int j)
{ a = i; b = j;
}
// Note: sum() is not a member function of any class.
int sum(myclass x)
{
/* Because sum() is a friend of myclass, it can directly access a and b. */
} return x.a + x.b; int main()
{ myclass n; n.set_ab(3, 4); cout << sum(n);
} return 0;
In this example, the sum( ) function is not a member of myclass. However, it still has full access to its private members. Also, notice that sum( ) is called without the use of the dot operator. Because it is not a member function, it does not need to be (indeed, it may not be) qualified with an object's name.
C h a p t e r 1 2 : C l a s s e s a n d O b j e c t s
299
Although there is nothing gained by making sum( ) a friend rather than a member function of myclass, there are some circumstances in which friend functions are quite valuable. First, friends can be useful when you are overloading certain types of operators
(see Chapter 14). Second, friend functions make the creation of some types of I/O functions easier (see Chapter 18). The third reason that friend functions may be desirable is that in some cases, two or more classes may contain members that are interrelated relative to other parts of your program. Let's examine this third usage now.
To begin, imagine two different classes, each of which displays a pop-up message on the screen when error conditions occur. Other parts of your program may wish to know if a pop-up message is currently being displayed before writing to the screen so that no message is accidentally overwritten. Although you can create member functions in each class that return a value indicating whether a message is active, this means additional overhead when the condition is checked (that is, two function calls, not just one). If the condition needs to be checked frequently, this additional overhead may not be acceptable. However, using a function that is a friend of each class, it is possible to check the status of each object by calling only this one function.
Thus, in situations like this, a friend function allows you to generate more efficient code. The following program illustrates this concept:
#include <iostream> using namespace std; const int IDLE = 0; const int INUSE = 1; class C2; // forward declaration class C1 { int status; // IDLE if off, INUSE if on screen
// ...
public:
}; void set_status(int state); friend int idle(C1 a, C2 b); class C2 { int status; // IDLE if off, INUSE if on screen
// ...
public:
}; void set_status(int state); friend int idle(C1 a, C2 b);
300
C + + : T h e C o m p l e t e R e f e r e n c e void C1::set_status(int state)
{ status = state;
} void C2::set_status(int state)
{ status = state;
} int idle(C1 a, C2 b)
{ if(a.status || b.status) return 0; else return 1;
} int main()
{
C1 x;
C2 y; x.set_status(IDLE); y.set_status(IDLE); if(idle(x, y)) cout << "Screen can be used.\n"; else cout << "In use.\n"; x.set_status(INUSE); if(idle(x, y)) cout << "Screen can be used.\n"; else cout << "In use.\n";
} return 0;
Notice that this program uses a forward declaration (also called a forward reference) for the class C2. This is necessary because the declaration of idle( ) inside C1 refers to C2 before it is declared. To create a forward declaration to a class, simply use the form shown in this program.
A friend of one class may be a member of another. For example, here is the preceding program rewritten so that idle( ) is a member of C1:
C h a p t e r 1 2 : C l a s s e s a n d O b j e c t s
301
#include <iostream> using namespace std; const int IDLE = 0; const int INUSE = 1; class C2; // forward declaration class C1 { int status; // IDLE if off, INUSE if on screen
// ...
public:
}; void set_status(int state); int idle(C2 b); // now a member of C1 class C2 { int status; // IDLE if off, INUSE if on screen
// ...
public:
}; void set_status(int state); friend int C1::idle(C2 b); void C1::set_status(int state)
{ status = state;
} void C2::set_status(int state)
{ status = state;
}
// idle() is member of C1, but friend of C2 int C1::idle(C2 b)
{ if(status || b.status) return 0; else return 1;
} int main()
{
Descargar
Anuncio