8.2.6 Objects, Inheritance, and References
) You might use ostream object cout and ofstream object fout(your declaration), and the object fout could share the methods of ostream class. The language features of passing class features from one to another is called class inheritance. In this example, ostream is termed base class and ofstream is termed derived class. Methods like precision() and setf() in ostream class is also available to ofstream class objects, so you could use same methods will handing console output and file output.
) A base class reference could refer to a derived class object without type cast.
The following example illustrates these features:
1 // filefunc.cpp -- function with ostream & parameter 2 #include <iostream> 3 #include <fstream> 4 #include <cstdlib> 5 using namespace std; 6 7 void file_it(ostream & os, double fo, const double fe[], int n); 8 const int LIMIT = 5; 9 int main() 10 { 11 ofstream fout; 12 const char * fn = "ep-data.txt"; 13 fout.open(fn); 14 if (!fout.is_open()) 15 { 16 cout << "Can't open " << fn << ". Bye.\n"; 17 exit(EXIT_FAILURE); 18 } 19 double objective; 20 cout << "Enter the focal length of your telescope objective in mm: "; 21 cin >> objective; 22 double eps[LIMIT]; 23 cout << "Enter the focal lengths, in mm, of " << LIMIT << " eyepieces:\n"; 24 for (int i = 0; i < LIMIT; i++) 25 { 26 cout << "Eyepiece #" << i+1 << ": "; 27 cin >> eps[i]; 28 } 29 file_it(fout, objective, eps, LIMIT); 30 file_it(cout, objective, eps, LIMIT); 31 cout << "Done\n"; 32 return 0; 33 } 34 35 void file_it(ostream & os, double fo, const double fe[], int n) 36 { 37 ios_base::fmtflags initial; 38 initial = os.setf(ios_base::fixed); // save initial formatting state 39 os.precision(0); 40 os << "Focal length of objective: " << fo << " mm\n"; 41 os.setf(ios::showpoint); 42 os.precision(1); 43 os.width(12); 44 os << "f.l. eyepiece"; 45 os.width(15); 46 os << "magnification" << endl; 47 for (int i = 0; i < n; i++) 48 { 49 os.width(12); 50 os << fe[i]; 51 os.width(15); 52 os << int(fo / fe[i] + 0.5) << endl; 53 } 54 os.setf(initial); 55 }
29-30) file_it() recieves an ostream-class reference as first parameter, here passes fout and cout consecutively, proving that base-class reference could also accpet derive-class objects without type cast, so these two lines print stuff on console and print it in a file, both using ostream class formatting features.
39/42) precision() specifies the number of digits displayed right to the decimal
43/45/49/51) width() specifies output width range for next output(width(0) means no mandatory stretch or trimming: just display it according to its original quantity)
37/38/54) Code like this is observed:
1 ios_base::fmtflags initial; 2 initial = os.setf(ios_base::fixed); 3 ... 4 os.setf(initial);
The first row declares a variable initial as type ios_base::fmtflags for storing initial pattern. Then initial was assigned to the return value of os.setf(), which returns the original format settings of the ostream object before "setf". After the process, it uses os.setf(initial) to retain the initial formatting by using the stored initial pattern.
8.2.7 When to Use Reference Arguments
There are two main reasons for using reference arguments:
1) To allow you to alter a data object in the calling function
2) To speed up the program by passing a reference instead of an entire data object
Guidelines of choosing between reference, pointer and passing by value:
No data modifying | modify data | |
build-in data type | pass by value | pointer |
array | const pointer | pointer |
structure | const pointer/reference | pointer/reference |
class object | const reference | reference |
8.3 Default Arguments
) A default argument is a value that's used automatically if you omit the corresponding actual argument from a function call.
) Use function prototype for default arguments.
char * left(const char * str, int n = 1);
In this way you make n a default argument, if you omit value of n, the program will take n for 1.
left(arr, 1); left(arr);// functions in the same way
) When using a function with an argument list, you must add defaults from left to right:
int f1(int n, int m = 4, int l = 5); // valid int f2(int n, int m = 3, int l); // invalid int f3(int n = 1, int m = 2, int l = 3); // valid
For instance, the f1() allows calls with one/two/three parameters. You can't skip arguments like this:
f1(2, , 3); // invalid, doesn't set m to 4
The following exapmle illustrates the features:
1 // left.cpp -- string function with a default argument 2 #include <iostream> 3 const int ArSize = 80; 4 char * left(const char * str, int n = 1); 5 int main() 6 { 7 using namespace std; 8 char sample[ArSize]; 9 cout << "Enter a string:\n"; 10 cin.get(sample, ArSize); 11 char *ps = left(sample, 4); 12 cout << ps << endl; 13 delete [] ps; 14 ps = left(sample); 15 cout << ps << endl; 16 delete [] ps; 17 return 0; 18 } 19 20 char * left(const char * str, int n) 21 { 22 if (n < 0) 23 n = 0; 24 char * p = new char[n+1]; 25 int i; 26 for (int i = 0; i < n && str[i]; i++) 27 p[i] = str[i]; 28 while (i <= n) 29 p[i++] = '\0'; 30 return p; 31 }