Review

We started the chapter with a simple inventory control example that used a StockItem class and an Inventory class, including a function called ReorderItem that can be called for an Inventory object to produce a reordering report. This function calls a Reorder function for each StockItem in its StockItem Vec to calculate the quantity of that StockItem to be ordered based on the desired and current stock.

Then we built on that StockItem class by adding an expiration date. Rather than copying all of the old code and class definitions, we made use of a concept that is essential to the full use of C++ for object-oriented programming — inheritance. Inheritance is a method of constructing one class (the derived class) by specifying how it differs from another class (the base class) rather than writing it from scratch. We used inheritance to create a new DatedStockItem class that had all of the capabilities of the StockItem class, adding the ability to handle items with expiration dates.

In the process, we wrote a new Reorder function with the same signature as that of the base class function of the same name. This is called overriding the base class function. When the function with that signature is called via an object of the base class, the base class function will be called. On the other hand, when the function with that signature is called via an object of the derived class, the derived class function will be called. This allows a derived class to supply the same functionality as that of a base class but to implement it in a different way.

A derived class object can do anything that a base class object can do because a derived class object actually contains an object of the base class, called the base class part of the derived class object. This base class part is very similar to a member variable in the derived class, but it is not the same for two reasons:

  1. A member variable always has a name, whereas the base class part does not.

  2. The base class definition can give derived class member functions privileged access to some member variables and functions of the base class part of an object of the derived class, by marking those member variables and functions with the access specifier keyword protected.

In the process of writing the new Reorder function for the DatedStockItem class, we saw how we could store a date as a string that allowed comparison of two dates to see which was later. This required us to create a formatted string representing the date as YYYYMMDD — that is, a four-digit year number, a two-digit month number, and a two-digit day number. Getting the current date wasn't too hard; we used the date variable type along with its associated getdate function to retrieve the year, month, and day of the current date. However, once we had this information, we still had to combine the parts of the date into a formatted string. One way to do this is to use the stringstream data type, which is a stream that exists only in memory as a formatting aid. This topic led to a discussion of how we can specify the formatting of data rather than accept the default formatting, as we did previously; it also led to the related discussion of using the stringstream class to generate formatted output.

After delving into the general topic of streams in more detail, we returned to the more specific issue of stringstreams, which allowed us to solve our formatting problem by combining the << operator with the manipulators setw and setfill to control the width and fill characters of the data we wrote to the stringstream.

Once we had used << to write the data to the stringstream in the required YYYYMMDD format, we used >> to read it back into a string for comparison with the expiration date stored in a DatedStockItem object (see Figures 9.28 and 9.29).

After discussing the formatting of the date string, we continued by examining the default constructor of the DatedStockItem class. While this is an extremely short function, having only one member initialization expression and no code in the constructor proper, there is more to it than meets the eye. The default constructor deals only with the newly added member variable, m_Expires, but behind the scenes the base class part of the DatedStockItem object is being initialized by the default constructor of the base classStockItem::StockItem(). The rule is that a base class constructor will always be called for the base class part of a derived class object. If we don't specify which base class constructor we want, the default constructor for the base class will be used. To select the constructor for the base class part, we can use a construct known as a base class initializer in the member initializer list in the derived class constructor. In our “normal” constructor for DatedStockItem, we used this construct to call the corresponding constructor for the base class (see Figures 9.33 and 9.34).

Then we looked at the Reorder function for the DatedStockItem class, which includes code to request the return of any items that are past their expiration date and calls the base class Reorder function to handle the rest of the job.

At that point, we had a working DatedStockItem class, but we still couldn't mix StockItem and DatedStockItem objects in the same Vec. However, it was possible to create a Vec of pointers to StockItems. Once we did that, we could make any of those pointers point to a DatedStockItem, employing the C++ feature that a base class pointer can also point to an object of a derived class. After seeing how to use operator new to allocate StockItem and DatedStockItem variables, we discovered that just using a base class pointer doesn't do what we wanted. As these classes are currently defined, the version of the Reorder function called through a StockItem pointer is always the base class version, rather than the correct version for the actual type of the object the pointer refers to. We'll see how to fix that problem in the next chapter.

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

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