2012年2月16日 星期四

Function Overloading


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:
  1. exact matches or trivial conversions (array names to pointers, a type to a const type)
  2. promotions - char to int, short to int, bool to int and float to double (not int to long)
  3. standard conversions – "demotions" , integral types to floating types, floating to integral
  4. user-defined conversion functions - constructors, conversion operators
  5. 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:
  1. copy one file to another
  2. append one file to another
  3. convert a file to uppercase
  4. convert a file to lowercase
  5. copy one file to another only if the target file does not exist
  6. copy part of one file to another (from line# to line#)
  7. copy part of one file to another (from line# to end of file)
  8. 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

沒有留言:

張貼留言