An overloaded function is one with different signatures. A function's signature is its argument list. For example,
void funk(int);
int funk(float);
int funk(int,float,char*);
These three functions have the same name, but different signatures. A signature represents a function's name and its argument list, not the return type. Consider,
void funky(int);
int funky(int);
These two functions have the same signature and could not be defined in the same program scope. In order to overload functions, they must have different signatures. Your compiler would not allow this.
Furthermore, functions with default arguments do not constitute different signatures, even though their function calls appear different. The functions
int flunk(int);
int flunk(int = 5);
may be called as: flunk(1) or flunk();
So, even though the function calls are unique, your compiler would disallow these definitions.
For overloaded functions, the compiler selects a function with the specified name and matching the argument list according to a "best match" criteria. The "best match" is made using the following order precedence:
- exact matches or trivial conversions (array names to pointers, a type to a const type)
- promotions - char to int, short to int, bool to int and float to double (not int to long)
- standard conversions – "demotions" , integral types to floating types, floating to integral
- user-defined conversion functions - constructors, conversion operators
- ellipsis - similar to the way printf and scanf work with a variable number of arguments. Example: void printf(...).
Function Overloading – Which function does the compiler select?
Suppose you have defined the following functions:
void funk();
void funk(int);
void funk(double);
Which function will the compiler select for these function calls?
funk() _____
funk(3) _____
funk(2.5) _____
Those are obvious – they are exact matches. What about these?
void funk(long);
void funk(double);
int x;
float f;
…
funk(x) _____ // This is an error – ambiguous function call
funk(f) _____ // promotes float to double__________________
Why is funk(x) an error and funk(f) a promotion?
What about these?
void funk(void);
void funk(float);
funk(2.5) _____ // This is __________________________________
funk(3) _____ // This is __________________________________
What about these?
void funk(int);
void funk(dog);
funk(2.5) _____ // This is __________________________________
funk(3) _____ // This is __________________________________
Example 6-1 - Function overloading – non-exact matches
This example demonstrates some function overloading and how the compiler handles non-exact matches.
1 // File: ex6-1.cpp - function overloading
2 #include <iostream>
3 using namespace std;
4
5 class X
6 {
7 public:
8 X(int) {}
9 };
10
11 void funk(int) { cout << "funk(int) called\n"; }
12 void funk(const double&) { cout << "funk(const double&) called\n";}
13
14 void gunk(double&) { cout << "gunk(double&) called\n"; }
15
16 void hunk(double) { cout << "hunk(double) called\n"; }
17
18 void junk(X) { cout << "junk(X) called\n"; }
19
20
21 int main()
22 {
23 double d;
24 const double cd = 7.5;
25 int i = 25;
26 short s = 6;
27 long l = 123456789;
28 float f = 2.65f; // note use of float suffix
29
30 funk(7); // exact match
31 funk(i); // exact match
32 funk(d); // trivial conversion
33 funk(s); // promotion
34 funk(cd); // exact match
35 // funk(l); error: ambiguity
36 funk(f); // See explanation below
37 // gunk(cd); error cannot convert const to non-const
38 // gunk(i); error cannot convert int to double&
39 hunk(i); // conversion
40 junk(i); // user-defined conversion
41 }****** Output ******
funk(int) called (30)
funk(int) called (31)
funk(const double&) called (32)
funk(int) called (33)
funk(const double&) called (34)
funk(const double&) called (36)
hunk(double) called (39)
junk(X) called (40)
Line 36: This is not a promotion. The float f cannot serve as a reference to a double, but, because the argument is reference to const, the compiler will create a temporary double (from f) and pass it by reference. What is the difference between this and line 37? Can't the compiler create a temporary double and pass it by reference? No, it doesn't work that way. If the argument is a reference to const, then a temporary can be created to serve as the reference. Who ever said this was going to be easy.
Example 6-2 - copyFile
This example makes use of function overloading. This purpose of this program is to build a copyfile command that may be used at the operating
system level. That is, it will emulate the DOS copy command or the UNIX cp command. Following the example code are sample command-line
compile commands that demonstrate compilation and linking for the command-line environment. The program also makes use of command-line
arguments.
The program allows the user to:
- copy one file to another
- append one file to another
- convert a file to uppercase
- convert a file to lowercase
- copy one file to another only if the target file does not exist
- copy part of one file to another (from line# to line#)
- copy part of one file to another (from line# to end of file)
- copy part of one file to another (from beginning of file to line#)
1 // File: ex6-2.cpp - overloaded functions
2
3 #include <cstdio>
4 #include <cstdlib>
5 #include <cstring>
6 #include <cctype>
7 using namespace std;
8
9 #ifdef __GNUG__
10 #include <unistd.h> // use this header file for Unix
11 #else
12 #include <io.h> // for access() function
13 #endif
14
15 // Overloaded function prototypes
16
17 int copyFile(const char* fn1,const char* fn2);
18 int copyFile(const char* fn1,const char* fn2,const char* option);
19 int copyFile(const char* fn1,const char* fn2,
20 const char* fromto, int lineno);
21 int copyFile(const char* fn1,const char* fn2,const char* from,
22 int line1,const char* to, int line2);
23
24 void errorMessage(char* msg);
25 void errorMessage(char* msg, FILE* fp1);
26 void errorMessage(char* msg, FILE* fp1, FILE* fp2);
27
28 // cmdArgsCheck() is not complete due to the length of the example
29 int cmdArgsCheck(char* /*argv*/ []) { return 1; } // assume OK
30
31 void displayCmdSyntax() {
32 fprintf(stderr,"Usage:\n");
33 fprintf(stderr,"\tcopyFile <file1> <file2>\n");
34 fprintf(stderr,"\tcopyFile <file1> <file2> -append\n");
35 fprintf(stderr,"\tcopyFile <file1> <file2> -upper\n");
36 fprintf(stderr,"\tcopyFile <file1> <file2> -lower\n");
37 fprintf(stderr,"\tcopyFile <file1> <file2> -noreplace\n");
38 fprintf(stderr,
39 "\tcopyFile <file1> <file2> -from <line#> -to <line#>\n");
40 fprintf(stderr,"\tcopyFile <file1> <file2> -from <line#>\n");
41 fprintf(stderr,"\tcopyFile <file1> <file2> -to <line#>\n");
42 }
43
44
45 int main(int argc, char* argv[])
46 {
47 if (argc<3 || *argv[1] == '?') {
48 displayCmdSyntax();
49 exit(0);
50 }
51
52 if (cmdArgsCheck(argv)==0) errorMessage("Invalid syntax\n");
53
54 switch (argc) {
55 case 3: copyFile(argv[1],argv[2]);
56 break;
57 case 4: copyFile(argv[1],argv[2],argv[3]);
58 break;
59 case 5: copyFile(argv[1],argv[2],argv[3],atoi(argv[4]));
60 break;
61 case 7: copyFile(argv[1],argv[2],argv[3],atoi(argv[4]),
62 argv[5],atoi(argv[6]));
63 break;
64 default: errorMessage("Error: Invalid syntax\n");
65 }
66
67 printf("Ok\n");
68 return 0;
69 }
70
71 // copies file fn1 to file fn2
72 void copyFile(const char* fn1, const char* fn2)
73 {
74 char buffer[256];
75 FILE * fp1, * fp2;
76
77 fp1 = fopen(fn1,"r");
78 if (!fp1) errorMessage("Unable to open input file\n");
79 fp2 = fopen(fn2,"w");
80 if (!fp2) errorMessage("Unable to open output file\n",fp1);
81
82 while (fgets(buffer,sizeof(buffer),fp1)) fputs(buffer,fp2);
83
84 fclose(fp1);
85 fclose(fp2);
86 }
87
88 // copies fn1 to file fn2 using append, upper, lower or noreplace
89 void copyFile(const char* fn1,const char* fn2,const char* option)
90 {
91 char buffer[256];
92 FILE * fp1, * fp2;
93 int status; // of fputs()
94
95 // check for valid option
96 if (strcmp(option,"-upper")==0 ||
97 strcmp(option,"-lower")==0 ||
98 strcmp(option,"-append")==0 ||
99 strcmp(option,"-noreplace")==0) /* keep going */ ;
100 else errorMessage("Invalid option");
101
102 fp1 = fopen(fn1,"r");
103 if (!fp1) errorMessage("Unable to open input file\n");
104
105 // append option
106 if (strcmp(option,"-append")==0) {
107 fp2 = fopen(fn2,"a");
108 if (!fp2) errorMessage("Unable to open output file\n",fp1);
109 else {
110 while (fgets(buffer,sizeof(buffer),fp1)) {
111 status = fputs(buffer,fp2);
112 if (status == EOF)
113 errorMessage("Unable to write to output file\n",fp1,fp2);
114 }
115 }
116 }
117 // upper & lower case options
118 if (strcmp(option,"-upper")==0 || strcmp(option,"-lower")==0) {
119 char ch;
120 fp2 = fopen(fn2,"w");
121 if (!fp2) errorMessage("Unable to open output file\n",fp1);
122 else {
123 while ((ch = getc(fp1)) != EOF) {
124 if (strcmp(option,"-upper")==0) putc(toupper(ch),fp2);
125 else putc(tolower(ch),fp2);
126 }
127 }
128 }
129
130 // noreplace option
131 if (strcmp(option,"-noreplace")==0) {
132
133 // check for the existence of file fn2
134 if (access(fn2,0)==0) // Note: access is non-ANSI
135 errorMessage("Noreplace error for output file\n",fp1);
136 else copyFile(fn1,fn2);
137 }
138 fclose(fp1);
139 fclose(fp2);
140 }
141
142 // copy part of fn1 to fn2 (from lineto or to lineno)
143 void copyFile(const char* fn1, const char* fn2,
144 const char* fromto, int lineno)
145 {
146 char buffer[256], *fgets_status, err_msg[80];
147 FILE * fp1, * fp2;
148 int i;
149
150 fp1 = fopen(fn1,"r");
151 if (!fp1) errorMessage("Unable to open input file\n");
152 fp2 = fopen(fn2,"w");
153 if (!fp2) errorMessage("Unable to open output file\n");
154
155 // copy "from" lineno to the end of file
156 if (strcmp(fromto,"from")==0) {
157 // read records up to "from"
158 for (i = 1; i<lineno;i++) {
159 fgets_status = fgets(buffer,sizeof(buffer),fp1);
160 if (!fgets_status) { // records are read up to "from"?
161 sprintf(err_msg,"Unable to read past record %d\n",i);
162 errorMessage(err_msg,fp1,fp2);
163 }
164 }
165 // read the rest of the file & write it out
166 while (fgets(buffer,sizeof(buffer),fp1)) fputs(buffer,fp2);
167 }
168
169
170 else if (strcmp(fromto,"to")==0) {
171 // read records up to "to" & write them out
172 for (i = 0; i<lineno;i++) {
173 fgets_status = fgets(buffer,sizeof(buffer),fp1);
174 if (!fgets_status) { // records are read up to "to"
175 sprintf(err_msg,"Unable to read past record %d\n",i);
176 errorMessage(err_msg,fp1,fp2);
177 }
178 fputs(buffer,fp2);
179 }
180 }
181 else errorMessage("Invalid syntax",fp1,fp2);
182
183 fclose(fp1);
184 fclose(fp2);
185 }
186
187 void copyFile(const char* fn1, const char* fn2,
188 const char* from, int line1, const char* to, int line2)
189 {
190 char buffer[256], err_msg[80], *fgets_status;
191 FILE * fp1, * fp2;
192 int i;
193
194 // check the syntax
195 if (strcmp(from,"from")||strcmp(to,"to"))
196 errorMessage("Invalid from/to syntax\n");
197
198 if (line1>line2) errorMessage("Invalid 'from' > 'to'\n");
199
200 fp1 = fopen(fn1,"r");
201 if (!fp1) errorMessage("Unable to open input file\n");
202 fp2 = fopen(fn2,"w");
203 if (!fp2) errorMessage("Unable to open output file\n");
204
205 // read records up to "from" line1
206 for (i = 1; i<line1;i++) {
207 fgets_status = fgets(buffer,sizeof(buffer),fp1);
208 if (!fgets_status) { // records are read up to "from"?
209 sprintf(err_msg,"Unable to read past record %d\n",i);
210 errorMessage(err_msg,fp1,fp2);
211 }
212 }
213
214 // read from “from” to “to” and write them out to a file
215 for (i = line1; i<=line2;i++) {
216 fgets_status = fgets(buffer,sizeof(buffer),fp1);
217 if (!fgets_status) { // records are read up to "to" ?
218 sprintf(err_msg,"Unable to read past record %d\n",i);
219 errorMessage(err_msg,fp1,fp2);
220 }
221 fputs(buffer,fp2);
222 }
223
224 fclose(fp1);
225 fclose(fp2);
226 }
227
228 void errorMessage(char* msg) {
229 fprintf(stderr,msg);
230 exit (-1);
231 }
232
233 void errorMessage(char* msg, FILE* fp1) {
234 fprintf(stderr,msg);
235 fclose(fp1);
236 exit (-1);
237 }
238
239 void errorMessage(char* msg, FILE* fp1, FILE* fp2) {
240 fprintf(stderr,msg);
241 fclose(fp1);
242 fclose(fp2);
243 exit (-1);
244 }Compile command for DOS using MS Visual C++ ver. 2008:
cl ex6-2.cpp /EHsc
Note: Before you can perform a command-line compile, you must run vcvars32.bat. This program and the cl.exe for the command-line compile are found in the directory:
\Program Files\Microsoft Visual Studio 9.0\VC\bin
Compile command for GNU (for DOS) compiler:
gxx -o cf.exe ex6-2.cpp -Wall
Compile command for GNU (for UNIX/Linux) compiler:
g++ ex6-2.cpp -o cf
****** Sample Program Run ******
C:\td124a>cf ?
Usage:
cf <file1> <file2>
cf <file1> <file2> -append
cf <file1> <file2> -upper
cf <file1> <file2> -lower
cf <file1> <file2> -noreplace
cf <file1> <file2> -from <line#> -to <line#>
cf <file1> <file2> -from <line#>
cf <file1> <file2> -to <line#>
C:\td124a>cf ex6-2.inp ex6-2.out
Ok
C:\td124a>cf ex6-2.inp ex6-2.out -from 2 -to 3
Ok
C:\td124a>cf ex6-2.inp ex6-2.out -noreplace
Noreplace error for output file
C:\td124a>cf ex6-2.inp ex6-2.out -form 2 -to 3
Invalid from/to syntax
沒有留言:
張貼留言