Reference Variables
A reference variable is an alias for another variable. It is similar to a pointer in that it contains the address of a variable, but unlike a pointer, you do not need to perform any dereferencing yourself.
Reference variables must be initialized when they are declared, and they cannot be reassigned to refer to another variable.
Examples:
float pie = 3.14;
float& apple = pie;
Here's a little piece of code that shows how a reference works, but it's not very realistic, because it doesn't make sense to use a reference for another variable in the same function.
int x = 5;
int &z = x; // z is another name for x
cout << x << endl; -> prints 5
cout << z << endl; -> prints 5
z = 9; // same as x = 9;
cout << x << endl; -> prints 9
cout << z << endl; -> prints 9
Important rule: You must initialize references.
You may not declare a reference variable, like this:
int& ri;
Don't confuse it with the legal declaration of a pointer:
int* pi;
Guideline: References are used as function arguments (or parameters) or return types.
Example 2-1
This example compares two swap functions. p_swap is written as the traditional swap function (that you would write in C). r_swap is the equivalent version which uses references. Note the advantage of using references:
1. you don't have to pass the address of a variable
2. you don't have to dereference the variable inside the called function.
1 // File: ex2-1.cpp Reference Variables - swap functions
2
3 #include <iostream>
4 using namespace std;
5
6 // Function prototypes (required in C++)
7 void pointerSwap(int*, int*);
8 void referenceSwap(int& i1, int& i2);
9
10 int main (void)
11 {
12 int x = 5;
13 int y = 7;
14
15 cout << x << ' ' << y << endl;
16
17 pointerSwap(&x,&y);
18
19 cout << x << ' ' << y << endl;
20
21 referenceSwap(x,y);
22
23 cout << x << ' ' << y << endl;
24
25 return 0;
26 }
27
28 void pointerSwap(int *a, int *b)
29 {
30 int temp;
31 temp = *a;
32 *a = *b;
33 *b = temp;
34 }
35
36 void referenceSwap(int &a, int &b)
37 {
38 int temp;
39 temp = a;
40 a = b;
41 b = temp;
42 } ***** Output *****
5 7
7 5 - line 19 output
5 7 - line 23 output
Program Analysis
This is an extensive analysis of this simple program. Probably more than you want to read about, but it should give you some ideas about how you should analyze an example. Some of the really obvious details were skipped, but you still thought about them.
Line 7 This, of course, is a prototype for a function that takes two pointer to int arguments. And, by the way what if the function prototype was written like?
void pointerSwap(int* n1, int* n2); or
void pointerSwap(int* a, int* b); or
void pointerSwap(int *n1, int *n2); or
void pointerSwap(int* n1, int *n2); or
void pointerSwap(int *, int *); or
It doesn't matter, they all mean the same thing. The * can be next to the int or next to a variable, or the variable doesn't even have to be there. This is just a style consideration.
Line 8 The int& function arguments mean that the arguments are references to int.
Line 17 Call the pointerSwap() function are pass in the addresses of two ints. Notice, that the was described (in the prototype discussion) as taking two pointer to int arguments, but when the function call is made here, you say that "the addresses of two ints" are passed in. You are, of course, familiar with this terminology from you C education.
Line 19 Here we see evidence that the pointer swap worked.
Line 21 In the call to the referenceSwap() function, note that the variable a just passed in (no addresses), just like a "pass by value". You know what that means, right?
Line 28 In the function definition heading, the function argument variable names do not have to match the variable names used in the function prototype. In the function argument, int *a, the * means that a is a pointer to an int, or the address of an int.
Line 31 *a, here means dereference a,or take the value stored at the pointer address.
Line 32 Notice, here, that *a can be used as an "L value". In the line above, it is used as an "R value".
Line 36 The argument, int &a (or int& a), means that a is a refererce to an int, or a refers to an int that exists elsewhere.
Line 39 Notice than when you use the reference, you don't need to defererence it. Herre's a secret – C++ accomplishes the reference utilization using pointers, but that none of your business!
It's often desirable to use a reference to a constant type to prevent changes to the referenced variable.
Example 2-2
This example shows function parameters passed as a reference and passed as a reference to const.
1 // File: ex2-2.cpp Reference Variables - function parameters
2
3 #include <iostream>
4 using namespace std;
5
6 void update_salary(double& sal)
7 {
8 sal *= 1.1;
9 return;
10 }
11
12 void display_salary(const double &sal)
13 {
14 cout << sal << endl;
15 return;
16 }
17
18
19 int main (void)
20 {
21 double salary = 50000.;
22
23 display_salary(salary);
24
25 update_salary(salary);
26
27 display_salary(salary);
28
29 return 0;
30 } With reference variables, the & may be attached to either the variable type or the variable name as demonstrated in this example.
It is not common practice to "directly" use reference to an array.
Example 2-3
This example illustrates the use of references as function parameters in an example that is a little more sophisticated. The purpose of the example is determine won, lost and tied statistics for some teams. The example is a little shallow, but it does make use of references to structs. Before you read the example, take a look at the sample program run at the end, so you get the gist of what it's trying to accomplish.
1 // File: ex2-3.cpp Reference Variables - function parameters
2
3 #include <iostream>
4 #include <cstring>
5 using namespace std;
6
7 const int NumTeams = 5; // better than #define NumTeams 5
8 const int NumScores = 11;
9
10 // a team struct contains a team name and its W-L-T totals
11 struct team {
12 char name[10];
13 unsigned won;
14 unsigned lost;
15 unsigned tied;
16 };
17
18 // the league struct contains an array of team structs
19 struct league {
20 team teams[NumTeams];
21 };
22
23 // this struct hold 2 team names and their points scored in a game
24 struct score {
25 char teamname[2][10];
26 unsigned points[2];
27 };
28
29 // function prototypes
30 void initializeLeague(league& L);
31 void enterScores(score* S);
32 int getTeamNumFromName(league& L, const char* Name);
33 void updateWonLostTied(league& L, score* S);
34 void printLeagueStats(league& L);
35
36 int main (void) {
37 league Birds;
38 score Scores[NumScores];
39
40 initializeLeague(Birds);
41 enterScores(Scores);
42 updateWonLostTied(Birds,Scores);
43 printLeagueStats(Birds);
44
45 return 0;
46 }
47
48 // Assign team names and zero out won, lost, tied
49 void initializeLeague(league& L) {
50 for (int i = 0; i < NumTeams; i++)
51 {
52 cout << "Enter team name => ";
53 cin >> L.teams[i].name;
54 L.teams[i].won = 0;
55 L.teams[i].lost = 0;
56 L.teams[i].tied = 0;
57 }
58 cout << endl << NumTeams << " teams initialized\n\n";
59 }
60
61 void enterScores(score* S) {
62 cout << "Enter " << NumScores << " scores:\n";
63 for (int i = 0; i < NumScores; i++)
64 {
65 cout << "<team #1> <score #1> <team #2> <score #2> => ";
66 cin >> S[i].teamname[0] >> S[i].points[0]
67 >> S[i].teamname[1] >> S[i].points[1];
68 }
69 cout << endl << NumScores << " scores entered\n\n";
70 }
71
72 // getTeamNumFromName() returns the index of the teams array
73 // (in the league struct) in which Name matchs the value
74 // of the league.teams[i].name. If no match is found, the
75 // function return -1
76 int getTeamNumFromName(league& L, const char* Name) {
77 for (int i = 0; i < NumTeams; i++)
78 {
79 if (strcmp(L.teams[i].name,Name) == 0) return i;
80 }
81 cerr << "Error: unable to find team: " << Name << endl;
82 return -1; // team name not found
83 }
84
85 void updateWonLostTied(league& L, score* S) {
86 int i,team0,team1;
87
88 for (i = 0; i < NumScores; i++) {
89 team0 = getTeamNumFromName(L,S[i].teamname[0]);
90 team1 = getTeamNumFromName(L,S[i].teamname[1]);
91
92 // if team name is bad, don't use the score
93 if (team0 == -1 || team1 == -1) continue;
94
95 if (S[i].points[0] > S[i].points[1]) { // team0 won
96 L.teams[team0].won++;
97 L.teams[team1].lost++;
98 }
99 if (S[i].points[0] < S[i].points[1]) { // team1 won
100 L.teams[team1].won++;
101 L.teams[team0].lost++;
102 }
103 if (S[i].points[0] == S[i].points[1]) { // tie game
104 L.teams[team0].tied++;
105 L.teams[team1].tied++;
106 }
107 }
108 }
109
110 void printLeagueStats(league& L) {
111 int i;
112 cout << "\nName\tWon\tLost\tTied\n";
113 for (i = 0; i < NumTeams; i++) {
114 cout << L.teams[i].name << '\t'
115 << L.teams[i].won << '\t'
116 << L.teams[i].lost << '\t'
117 << L.teams[i].tied << '\n';
118 }
119 } ***** Sample Run *****
50000
55000
/************************ Sample Run ****************************
Enter team name => coots
Enter team name => ducks
Enter team name => eagles
Enter team name => finches
Enter team name => geese
5 teams initialized
Enter 11 scores:
<team #1> <score #1> <team #2> <score #2> => coots 5 ducks 2
<team #1> <score #1> <team #2> <score #2> => coots 3 eagles 7
<team #1> <score #1> <team #2> <score #2> => coots 1 finches 0
<team #1> <score #1> <team #2> <score #2> => coots 0 geese 0
<team #1> <score #1> <team #2> <score #2> => ducks 1 eagles 4
<team #1> <score #1> <team #2> <score #2> => ducks 5 finches 2
<team #1> <score #1> <team #2> <score #2> => ducks 2 geese 1
<team #1> <score #1> <team #2> <score #2> => eagles 7 finches 7
<team #1> <score #1> <team #2> <score #2> => eagles 8 geese 5
<team #1> <score #1> <team #2> <score #2> => finches 3 geese 2
<team #1> <score #1> <team #2> <score #2> => gooses 9 ducks 2
11 scores entered
Error: unable to find team: gooses
Name Won Lost Tied
coots 2 1 1
ducks 2 2 0
eagles 3 0 1
finches 1 2 1
geese 0 3 1
******************************************************************/
C++ 的 reference 類似 C 的 point, 但 reference 必須起始化; 且 reference 通常用於 function arguments 和 return type. 最常見的例子就是 swap 的運用.
沒有留言:
張貼留言