A friend function is a non-member function that has access to the private parts of a class. Friendship can be granted in three ways:
- to an independent (non-class member) function
- to a class member function of another class
- to another class (to all functions in that class)
A friend function is always a non-class member. A function outside of a class cannot "seek friendship". Friendship is only granted by a class to another function (or class). A friend has access to all private members.
It is common practice for friend functions to have arguments which include references to the (friendship-granting) class.
Example 5-5 - An independent friend
1 // File: ex5-5.cpp
2
3 #include <iostream>
4 using namespace std;
5
6 class circle
7 {
8 friend void print(const circle&); // name a friend of the class
9 public:
10 circle (double r) { radius = r;}
11 private:
12 double radius;
13 };
14
15 int main(void)
16 {
17 circle c1(5.);
18 print(c1); // prints This circle has radius 5
19 circle c2(1.);
20 print(c2); // prints This circle has radius 1
21 return 0;
22 }
23
24 void print(const circle& c)
25 {
26 cout << "This circle has radius " << c.radius << endl;
27 }Friendly advice
- Friend functions are not affected by their location in a class definition or any access specifiers.
- Granting friendship to another function or class is not reciprocal. If class xyz declares that class abc is a friend, then class xyz is not necessarily a friend to class abc.
- Friendship is not transitive. If class xyz grants friendship to class abc, and class abc grants friendship to class def, then the friendship from xyz is not automatically granted to def.
- Friendship is not inherited. The friend of a base class is not a friend to a class derived from the base. Further, if a base class, B, is a friend to another class, C, classes derived from B are not friends of C. (My friends are not necessarily my children's friends, and my children's friends are not my friends.)
- Class member functions operate on the object that invokes the function. Friend functions operate on objects that are passed as arguments.
Granting friendship to another class
- If class dog grants friendship to class cat, then any function of the cat class can access any member of the dog class.
- The word class is optional in the grant of friendship to another class.
Granting friendship to a function of another class
- To grant friendship to a member of another class, you must indicate the class name and function name using the scope resolution operator.
- If you want the dog class to grant friendship to the meow function of the cat class, you must:
- forward declare the dog class.
- define the cat class, declaring the meow function, but not defining it.
- define the dog class, identifying the friend function, cat::meow().
- define the cat member functions.
1 // File: ex5-6.cpp - a friend to the card and deck classes
2
3 #include <iostream>
4 #include <stdlib> // needed for rand() function
5 using namespace std;
6
7 const char* value_name[13] = {"two","three","four","five","six",
8 "seven","eight","nine","ten","jack","queen","king","ace"};
9
10 const char* suit_name[4] = {"clubs","diamonds","hearts","spades"};
11
12 const int HandSize = 5;
13 const int DeckSize = 52;
14
15 class deck; // What’s this?
16
17 class hand
18 {
19 private:
20 int card_no[HandSize];
21 public:
22 hand() { }
23 void dealMe(deck&);
24 void print(const deck&) const;
25 };
26
27 class card
28 {
29 private:
30 int value;
31 int suit;
32 public:
33 card() { }
34 void assign(int);
35 int get_value(void) const { return value;}
36 int get_suit(void) const { return suit;}
37 void print(void) const;
38 friend void hand::print(const deck&) const;
39 };
40
41 void card::assign(int x) // why not use the ctor?
42 {
43 value = x % 13;
44 suit = x % 4;
45 }
46
47 void card::print(void) const
48 {
49 cout << value_name[value] << " of " << suit_name[suit] << endl;
50 }
51 class deck {
52 friend class hand;
53 private:
54 card d[DeckSize];
55 int next_card;
56 public:
57 deck(void);
58 void shuffle(void);
59 void deal(int=HandSize);
60 void print(void) const;
61 };
62
63 deck::deck(void)
64 {
65 for (int i = 0; i < DeckSize; i++) d[i].assign(i);
66 next_card = 0;
67 }
68
69 void deck::shuffle(void)
70 {
71 int i, k;
72 card temp;
73 cout << "I am shuffling the deck\n";
74 for (i = 0; i < DeckSize; i++)
75 {
76 k = rand() % DeckSize;
77 temp = d[i];
78 d[i] = d[k];
79 d[k] = temp;
80 }
81 }
82
83 void deck::print(void) const
84 {
85 int i;
86 for (i = 0; i < DeckSize; i++) d[i].print();
87 }
88
89 void hand::dealMe(deck& dk) // why isn’t dk const deck& ?
90 {
91 int i;
92 for (i = 0; i < HandSize; i++) card_no[i] = dk.next_card++;
93 return;
94 }
95
96 void hand::print(const deck& dk) const
97 {
98 int i;
99 cout << "here is your hand:\n";
100 for (i = 0; i < HandSize; i++) dk.d[card_no[i]].print();
101 }
102 int main (void) {
103 deck poker;
104 poker.shuffle();
105 poker.print();
106 hand Joe;
107 hand Mary;
108 Joe.dealMe(poker);
109 Mary.dealMe(poker);
110 cout << "\nOk, Joe ";
111 Joe.print(poker);
112 cout << "\nOk, Mary ";
113 Mary.print(poker);
114 return 0;
115 }****** Output ******
I am shuffling the deck
ten of hearts
ace of diamonds
queen of hearts
three of hearts
four of diamonds
eight of diamonds
eight of spades
eight of hearts
seven of spades
six of hearts
.
.
.
Ok, Joe here is your hand:
ten of hearts
ace of diamonds
queen of hearts
three of hearts
four of diamonds
Ok, Mary here is your hand:
eight of diamonds
eight of spades
eight of hearts
seven of spades
six of hearts
Does hand::print() have to be declared as a friend of the card class?
How can you change the code to eliminate all friend functions?
Example 5-7 - More friendly poker
1 // File: ex5-7.cpp
2
3 #include <iostream>
4 #include <cstdlib> // needed for rand() function
5 #include <cstring>
6 #include <cassert>
7 using namespace std;
8
9 const int HandSize = 5;
10 const int DeckSize = 52;
11 const char* value_name[13] = {"two","three","four","five","six",
12 "seven","eight","nine","ten","jack","queen","king","ace"};
13 const char* suit_name[4] = {"clubs","diamonds","hearts","spades"};
14
15 class deck;
16
17 class hand
18 {
19 friend void threeOrFourOfAKind(const deck& d,const hand&);
20 private:
21 char* name;
22 int card_no[5];
23 public:
24 hand(void);
25 ~hand();
26 void dealMe(deck&);
27 void print(const deck&) const;
28 char* getName(void) {return name;}
29 };
30
31 hand::hand(void) {
32 char temp[32];
33 cout << "Enter player name => ";
34 cin >> temp;
35 name = new char[strlen(temp) + 1];
36 strcpy(name,temp);
37 }
38
39 hand::~hand() {
40 delete [] name;
41 }
42
43 class card
44 {
45 private:
46 int value;
47 int suit;
48 public:
49 card () { }
50 void assign(int);
51 int get_value(void) const { return value;}
52 int get_suit(void) const { return suit;}
53 void print(void) const;
54 };
55 void card::assign(int x) {
56 value = x % 13;
57 suit = x % 4;
58 }
59
60 void card::print(void) const {
61 cout << value_name[value] << " of " << suit_name[suit] << endl;
62 }
63
64 class deck
65 {
66 friend void threeOrFourOfAKind(const deck&,const hand&);
67 friend class hand;
68 private:
69 card d[DeckSize];
70 int next_card;
71 void shuffle(void);
72 public:
73 deck();
74 void print(void) const;
75 };
76
77 deck::deck() {
78 int i;
79 for (i = 0; i < DeckSize; i++) d[i].assign(i);
80 next_card = 0;
81 shuffle();
82 }
83
84 void deck::shuffle(void) {
85 int i,k;
86 card temp;
87 cout << "I am shuffling the deck\n";
88 for (i = 0; i < DeckSize; i++)
89 {
90 k = rand() % DeckSize;
91 temp = d[i];
92 d[i] = d[k];
93 d[k] = temp;
94 }
95 }
96
97 void deck::print(void) const {
98 int i;
99 for (i = 0; i < DeckSize; i++) d[i].print();
100 }
101
102 void hand::dealMe(deck& dk) {
103 int i;
104 assert(dk.next_card < DeckSize-4);
105 for (i = 0; i < HandSize; i++) card_no[i] = dk.next_card++;
106 }
107
108 void hand::print(const deck& dk) const {
109 int i;
110 for (i = 0; i < HandSize; i++) dk.d[card_no[i]].print();
111 }
112
113 int main (void) {
114 deck poker;
115
116 hand player[3];
117 int i;
118 for (i = 0; i < 3; i++) player[i].dealMe(poker);
119 for (i = 0; i < 3; i++)
120 {
121 cout << "\nOk " << (player[i].getName())
122 << ", here is your hand\n";
123 player[i].print(poker);
124 threeOrFourOfAKind(poker,player[i]);
125 }
126 return 0;
127 }
128
129 void threeOrFourOfAKind(const deck& dk,const hand& who) {
130 int temp;
131 int card_count;
132 for (int i = 0; i < 3; i++)
133 {
134 card_count = 1;
135 temp = (dk.d[who.card_no[i]]).get_value();
136 for (int j = i + 1; j < HandSize; j++)
137 if (temp==dk.d[who.card_no[j]].get_value()) card_count++;
138 if (card_count > 2)
139 {
140 cout << "Hey, " << (who.getName()) << ", you have "
141 <<card_count << ' ' << value_name[temp] << "s.\n";
142 return;
143 }
144 }
145 return;
146 }****** Sample Run ******
I am shuffling the deck
Enter player name => Joe
Enter player name => Mabel
Enter player name => Bob
Ok Joe, here is your hand
ten of hearts
ace of diamonds
queen of hearts
three of hearts
four of diamonds
Ok Mabel, here is your hand
eight of diamonds
eight of spades
eight of hearts
seven of spades
six of hearts
Hey, Mabel, you have 3 eights.
Ok Bob, here is your hand
five of clubs
jack of clubs
jack of spades
ace of hearts
king of clubs
沒有留言:
張貼留言