Objectives of This Chapter

By the end of this chapter, you should

  1. understand how we can use inheritance to create a new class by extending an existing class, and

  2. understand how to use manipulators to control the format of iostream output.

Two Reasons to Use Inheritance

Before we return to the detailed examination of our inventory control classes (StockItem and its companion class Inventory) let's expand a bit on the first objective as it applies to this case.

There are two reasons to use inheritance. The first is to create a new class that has all of the capabilities of an existing class while adding capabilities that are unique to the new class. In such a case, objects of the new class are clearly not equivalent to objects of the existing class, which means that the user of these classes has to know which class any given object belongs to so that he or she can tell which operations that object can perform. We could call this use of inheritance “inheritance for extension”. It's illustrated by one of the Employee class exercises in this chapter.[1]

[1] As elsewhere in this book, when I speak of the “user” of a class, I mean the application programmer who is using objects of the class to perform work in his or her program, not the “end user” who is using the finished program.

In the current case, however, we'll be using inheritance to create a new class called DatedStockItem that will behave exactly like the StockItem class except that its items will have expiration dates. As a result, the user of these classes will be able to treat objects of the new DatedStockItem class in the same way as those of the base class. Of course, to create an object of this new class, the expiration date for the object must be provided, but once such an object exists its user can view it exactly as if it were as an object of the base class, which makes this an example of “inheritance for reimplementation”. In such a case, it is reasonable to be able to substitute objects of the derived class for those of the base class. This relationship between a base class and a derived class is commonly expressed by saying that the derived class “isA” base class object. We will see how to use that characteristic of inheritance in the next chapter.

Before we can do that, though, we'll need to learn how to create a new class by derivation from an existing class. In this case, we're going to start with a version of our previous StockItem class that has been extended slightly to include a Reorder function that generates a reordering report when we get low on an item, as well as some new input and output facilities. We'll also need to improve on our companion Inventory class, which as before we'll use to keep track of all the StockItems in the store.

Now let's get to the details of how this version of the StockItem class works. Figure 9.1 shows the header file for that class.

Here's a rundown on the various member functions of the StockItem class, including those that we've already seen:

  1. StockItem(); is the default constructor.

  2. StockItem(string Name, short InStock, short Price, short MinimumStock, short MinimumReorder, string Distributor, string UPC); is the normal constructor, which has a couple of new arguments, MinimumStock and MinimumReorder, which are needed for the reordering function.

  3. void FormattedDisplay(ostream& os); displays the member variables of a StockItem object with labels so you can tell which value is for which member variable.

  4. bool CheckUPC(string ItemUPC); returns true if its argument is the same as the UPC (i.e., the m_UPC member variable) of its StockItem.

  5. void DeductSaleFromInventory(short QuantitySold); reduces the inventory (i.e., the value of the m_InStock member variable) by the value of its argument.

  6. short GetInventory(); returns the number of items in stock for this StockItem (i.e., the value of the m_InStock member variable).

  7. string GetName(); returns the name of the StockItem (i.e., the value of the m_Name member variable).

  8. string GetUPC(); returns the UPC of the StockItem (i.e., the value of the m_UPC member variable).

  9. bool IsNull(); returns true if this is a “null StockItem”. This can happen, for example, when a StockItem is returned as a “not found” value by a search.

  10. short GetPrice(); returns the price of the StockItem (i.e., the value of the m_Price member variable).

  11. void Reorder(ostream& os); generates a reorder report based on the relationship of the number in stock (m_InStock) versus the minimum desired stock (m_MinimumStock), taking the minimum reorder quantity (m_MinimumReorder) into account.

Figure 9.1. The next StockItem header file (codeitem20.h)
class StockItem
{
friend std::ostream& operator << (std::ostream& os,
  const StockItem& Item);

friend std::istream& operator >> (std::istream& is, StockItem& Item);

public:
  StockItem();

  StockItem(std::string Name, short InStock,
  short Price, short MinimumStock,
  short MinimumReorder, std::string Distributor, std::string UPC);

  void FormattedDisplay(std::ostream& os);
  bool CheckUPC(std::string ItemUPC);
  void DeductSaleFromInventory(short QuantitySold);
  short GetInventory();
  std::string GetName();
  std::string GetUPC();
  bool IsNull();
  short GetPrice();

  void Reorder(std::ostream& os);

private:
  short m_InStock;
  short m_Price;
  short m_MinimumStock;
  short m_MinimumReorder;
  std::string m_Name;
  std::string m_Distributor;
  std::string m_UPC;
};


Here's a brief description of the input/output operators for this class, which will allow us to read and write its objects in much the same way as we can do with the built-in types and the string class we've created earlier in the book:

  1. friend ostream& operator << (ostream& os, const StockItem& Item); sends a human-readable version of the state of a StockItem object to the ostream specified as the left-hand argument to <<. This is analogous to the use of operator << for output of the built-in types.

  2. friend istream& operator >> (istream& is, StockItem& Item); creates a StockItem object by reading a human-readable version of the state of the object from the istream specified as the left-hand argument to >>. This is analogous to the use of operator >> for input of the built-in types.

Susan wanted to know why we needed the FormattedDisplay function.

Susan: Do we need the FormattedDisplay to make the data appear on the screen the way we want it? I mean, does the FormattedDisplay function do something that we can't do by just using operator <<?

Steve: Yes. It puts labels on the data members so you can tell what they are.

Figure 9.2 shows the implementation of the StockItem class that we will start our inheritance exercise from.

Figure 9.2. The next implementation of StockItem (codeitem20.cpp)
#include <iostream>
#include <string>
#include "item20.h"
using namespace std;

StockItem::StockItem()
: m_InStock(0), m_Price(0), m_MinimumStock(0),
  m_MinimumReorder(0), m_Name(), m_Distributor(),
  m_UPC()
{
}

StockItem::StockItem(string Name, short InStock,
short Price, short MinimumStock,
short MinimumReorder, string Distributor, string UPC)
: m_InStock(InStock), m_Price(Price),
  m_MinimumStock(MinimumStock),
  m_MinimumReorder(MinimumReorder), m_Name(Name),
  m_Distributor(Distributor), m_UPC(UPC)
{
}

void StockItem::FormattedDisplay(ostream& os)
{
  os << "Name: ";
  os << m_Name << endl;
  os << "Number in stock: ";
  os << m_InStock << endl;
  os << "Price: ";
  os << m_Price << endl;
  os << "Minimum stock: ";
  os << m_MinimumStock << endl;
  os << "Minimum Reorder quantity: ";
  os << m_MinimumReorder << endl;
  os << "Distributor: ";
  os << m_Distributor << endl;
  os << "UPC: ";
  os << m_UPC << endl;
}

ostream& operator << (ostream& os, const StockItem& Item)
{
  os << Item.m_Name << endl;
  os << Item.m_InStock << endl;
  os << Item.m_Price << endl;
  os << Item.m_MinimumStock << endl;
  os << Item.m_MinimumReorder << endl;
  os << Item.m_Distributor << endl;
  os << Item.m_UPC << endl;

  return os;
}

istream& operator >> (istream& is, StockItem& Item)
{
  getline(is,Item.m_Name);
  is >> Item.m_InStock;
  is >> Item.m_Price;
  is >> Item.m_MinimumStock;
  is >> Item.m_MinimumReorder;
  is.ignore();
  getline(is,Item.m_Distributor);
  getline(is,Item.m_UPC);
  return is;
}

bool StockItem::CheckUPC(string ItemUPC)
{
  if (m_UPC == ItemUPC)
    return true;

  return false;
}

void StockItem::DeductSaleFromInventory(short QuantitySold)
{
  m_InStock -= QuantitySold;
}

short StockItem::GetInventory()
{
  return m_InStock;
}

string StockItem::GetName()
{
  return m_Name;
}

string StockItem::GetUPC()
{
  return m_UPC;
}

bool StockItem::IsNull()
{
  if (m_UPC == "")
    return true;

  return false;
}

short StockItem::GetPrice()
{
  return m_Price;
}

void StockItem::Reorder(ostream& os)
{
  short ActualReorderQuantity;

  if (m_InStock < m_MinimumStock)
    {
    ActualReorderQuantity = m_MinimumStock - m_InStock;
    if (m_MinimumReorder > ActualReorderQuantity)
      ActualReorderQuantity = m_MinimumReorder;
    os << "Reorder " << ActualReorderQuantity;
    os <<  " units of " << m_Name;
    os << " with UPC " << m_UPC;
    os << " from " << m_Distributor << endl;
    }
}

Susan had a lot of questions about the operator << and operator >> functions for this class as well as about streams in general.

Susan: Why do you have to define these functions again?

Steve: They have to be defined for every class of objects we want to be able to use them for. After all, every class of objects has different data items in it; how is a stream supposed to know how to read or write some object that we've made up, unless we tell it how to?

Susan: What's “is” again? I forgot. :-P

Steve: The istream that we're using to get the data for the StockItem.

Susan: So, it's just a file? Is it always called is?

Steve: No, it's not a file; it's an istream, which is an object connected to a file that allows us to read from the file using >>.

Susan: Do you mean any file that has >> or <<? If it is like an istream where does the data end up? Just how does it work? When does the istream start flowing and at what point does the data jump in and get out? What is the istream doing when there is no data to be transported? Where is it flowing? If it is not a file, then where is it stored? So, whenever you read something from an istream, is it always called “is”?

Steve: Obviously streams are going to take a lot more explaining, with pictures. We'll get to it later in this chapter.[2]

[2] See “The stream classes” on page 617.

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

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