Another Object Lesson: Objects, Inheritance, and References

The ostream and ofstream classes bring an interesting property of references to the fore. As you may recall from Chapter 6, “Branching Statements and Logical Operators,” objects of the ofstream type can use ostream methods, allowing file input/output to use the same forms as console input/output. The language feature that makes it possible to pass features from one class to another is called inheritance, and Chapter 13, “Class Inheritance,” discusses this feature in detail. In brief, ostream is termed a base class (because the ofstream class is based on it) and ofstream is termed a derived class (because it is derived from ostream). A derived class inherits the base class methods, which means that an ofstream object can use base class features such as the precision() and setf() formatting methods.

Another aspect of inheritance is that a base class reference can refer to a derived class object without requiring a type cast. The practical upshot of this is that you can define a function having a base class reference parameter, and that function can be used with base class objects and also with derived objects. For example, a function with a type ostream & parameter can accept an ostream object, such as cout, or an ofstream object, such as you might declare, equally well.

Listing 8.8 demonstrates this point by using the same function to write data to a file and to display the data onscreen; only the function call argument is changed. This program solicits the focal length of a telescope objective (its main mirror or lens) and of some eyepieces. Then it calculates and displays the magnification each eyepiece would produce in that telescope. The magnification equals the focal length of the telescope divided by the focal length of the eyepiece used, so the calculation is simple. The program also uses some formatting methods, which, as promised, work equally well with cout and with ofstream objects (fout, in this example).

Listing 8.8. filefunc.cpp


//filefunc.cpp -- function with ostream & parameter
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;

void file_it(ostream & os, double fo, const double fe[],int n);
const int LIMIT = 5;
int main()
{
    ofstream fout;
    const char * fn = "ep-data.txt";
    fout.open(fn);
    if (!fout.is_open())
    {
        cout << "Can't open " << fn << ". Bye. ";
        exit(EXIT_FAILURE);
    }
    double objective;
    cout << "Enter the focal length of your "
            "telescope objective in mm: ";
    cin >> objective;
    double eps[LIMIT];
    cout << "Enter the focal lengths, in mm, of " << LIMIT
         << " eyepieces: ";
    for (int i = 0; i < LIMIT; i++)
    {
        cout << "Eyepiece #" << i + 1 << ": ";
        cin >> eps[i];
    }
    file_it(fout, objective, eps, LIMIT);
    file_it(cout, objective, eps, LIMIT);
    cout << "Done ";
    return 0;
}

void file_it(ostream & os, double fo, const double fe[],int n)
{
    ios_base::fmtflags initial;
    initial = os.setf(ios_base::fixed); // save initial formatting state
    os.precision(0);
    os << "Focal length of objective: " << fo << " mm ";
    os.setf(ios::showpoint);
    os.precision(1);
    os.width(12);
    os << "f.l. eyepiece";
    os.width(15);
    os << "magnification" << endl;
    for (int i = 0; i < n; i++)
    {
        os.width(12);
        os << fe[i];
        os.width(15);
        os << int (fo/fe[i] + 0.5) << endl;
    }
    os.setf(initial);   // restore initial formatting state
}


Here is a sample run of the program in Listing 8.8:

Enter the focal length of your telescope objective in mm: 1800
Enter the focal lengths, in mm, of 5 eyepieces:
Eyepiece #1: 30
Eyepiece #2: 19
Eyepiece #3: 14
Eyepiece #4: 8.8
Eyepiece #5: 7.5
Focal length of objective: 1800 mm
f.l. eyepiece  magnification
        30.0             60
        19.0             95
        14.0            129
         8.8            205
         7.5            240
Done

The following line writes the eyepiece data to the file ep-data.txt:

file_it(fout, objective, eps, LIMIT);

And this line writes the identical information in the identical format to the screen:

file_it(cout, objective, eps, LIMIT);

Program Notes

The main point of Listing 8.8 is that the os parameter, which is type ostream &, can refer to an ostream object such as cout and to an ofstream object such as fout. But the program also illustrates how ostream formatting methods can be used for both types. Let’s review, or, in some cases, examine for the first time, some of these methods. (Chapter 17, “Input, Output, and Files,” provides a fuller discussion.)

The setf() method allows you to set various formatting states. For example, the method call setf(ios_base::fixed) places an object in the mode of using fixed decimal-point notation. The call setf(ios_base:showpoint) places an object in the mode of showing a trailing decimal point, even if the following digits are zeros. The precision() method indicates the number of figures to be shown to the right of the decimal (provided that the object is in fixed mode). All these settings stay in place unless they’re reset by another method call. The width() call sets the field width to be used for the next output action. This setting holds for displaying one value only, and then it reverts to the default. (The default is a field width of zero, which is then expanded to just fit the actual quantity being displayed.)

The file_it() function uses an interesting pair of method calls:

ios_base::fmtflags initial;
initial = os.setf(ios_base::fixed); // save initial formatting state
...
os.setf(initial);   // restore initial formatting state

The setf() method returns a copy of all the formatting settings in effect before the call was made. ios_base::fmtflags is a fancy name for the type needed to store this information. So the assignment to initial stores the settings that were in place before the file_it() function was called. The initial variable can then be used as an argument to setf() to reset all the formatting settings to this original value. Thus, the function restores the object to the state it had before being passed to file_it().

Knowing more about classes will help you understand better how these methods work and, why, for example, ios_base keeps popping up. But you don’t have to wait until Chapter 17 to use these methods.

One final point: Each object stores its own formatting settings. So when the program passes cout to file_it(), cout’s settings are altered and then restored. When the program passes fout to file_it(), fout’s settings are altered and then restored.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.148.104.124