Class Inheritance Example
Spring 2002
Table of Contents
1. Introduction
2. Source Code
Instructor Comments
Section 1. Introduction

This is an example of inheritance. It is not a particularly good example from a design standpoint, but it is here as a starting point for discussing the DesktopItem example that demonstrates polymorphism.

Section 2. Source Code
TextDoc.h
   1// TextDoc.h
   2// Author: t a y l o r@msoe.edu and section 6 of the MSOE Spring 2002 CS183 course
   3// Date: 4-16-2002
   4// Purpose: Defines a TextDoc class which represents a text document.
   5
   6#ifndef TEXTDOC_H
   7#define TEXTDOC_H
   8
   9#include <string>
  10using std::string;
  11
  12class TextDoc {
  13public:
  14  // Constructor... pass in the document name
  15  TextDoc(const string& name);
  16
  17  // Copy constructor
  18  TextDoc(const TextDoc& rhs);
  19
  20  // Destructor
  21  ~TextDoc();
  22
  23  // Assignment operator
  24  TextDoc& operator=(const TextDoc& rhs);
  25
  26  // Returns a const reference to the text contained in the TextDoc object
  27  const string& contents() const;
  28
  29  // Returns a reference to the text contained in the TextDoc object
  30  string& contents();
  31
  32  // Returns the TextDoc object's name
  33  const string& getDocName() const;
  34
  35  // Saves TextDoc to disk, returns true if successful
  36  bool save() const;
  37
  38  // Changes the name of the TextDoc and saves TextDoc to disk, returns
  39  //  true if successful
  40  bool saveAs(const string& name);
  41
  42  // Returns the number of bytes required to store the TextDoc object
  43  unsigned int size() const;
  44protected:
  45  // Declared protected because TextDoc objects must have a name when created
  46  TextDoc();
  47
  48  string text;
  49  string docName;
  50};
  51
  52#endif
Folder.h
   1// Folder.h
   2// Author: t a y l o r@msoe.edu and section 6 of the MSOE Spring 2002 CS183 course
   3// Date: 4-16-2002
   4// Purpose: Defines a Folder class which represents a file system folder
   5//          that stores text documents (TextDoc objects).
   6
   7#ifndef FOLDER_H
   8#define FOLDER_H
   9
  10#include <string>
  11#include <list>
  12#include "TextDoc.h"
  13
  14using std::string;
  15using std::list;
  16
  17class Folder {
  18public:
  19  // Constructor... pass in the folder name
  20  Folder(const string& name);
  21
  22  // Copy constructor
  23  Folder(const Folder& rhs);
  24
  25  // Destructor
  26  ~Folder();
  27
  28  // Assignment operator
  29  Folder& operator=(const Folder& rhs);
  30
  31  // Returns the folder's name
  32  const string& getFolderName() const;
  33
  34  // Searches for a text document with the same name as td.  If none exists,
  35  //  td is added to the list of folders and true is returned.  Otherwise,
  36  //  it returns false.
  37  bool add(const TextDoc& td);
  38
  39  // Searches for a text document called name.  If one is found, it removes
  40  //  it from the SuperFolder object and returns true.  Otherwise, it
  41  //  returns false.
  42  bool removeDoc(const string& name);
  43
  44  // Searches for a text document called name.  If one is found, it returns
  45  //  a copy of it.  Otherwise it returns an empty text document.
  46  TextDoc getDoc(const string& name) const;
  47
  48  // Returns the number of text documents contained in folder
  49  unsigned int getNumItems() const;
  50
  51  // Returns the number number of bytes required to store the contents of
  52  //  the folder
  53  unsigned int size() const;
  54protected:
  55  // Declared protected because Folder objects must have a name when created
  56  Folder();
  57
  58  string fname;
  59  list<TextDoc> docs;
  60};
  61
  62#endif
SuperFolder.h
   1// SuperFolder.h
   2// Author: t a y l o r@msoe.edu and section 6 of the MSOE Spring 2002 CS183 course
   3// Date: 4-16-2002
   4// Purpose: Defines a SuperFolder class which represents a file system
   5//          folder that can store text files (TextDoc objects) and
   6//          subfolders (Folder objects).
   7
   8#ifndef SUPERFOLDER_H
   9#define SUPERFOLDER_H
  10
  11#include <string>
  12#include <list>
  13#include "Folder.h"
  14
  15using std::string;
  16using std::list;
  17
  18class SuperFolder : public Folder {

The previous line indicates that the Folder class should be inherited by the SuperFolder class. As a result, all member functions and data members from the Folder class are now part of the SuperFolder class.

All public members of the Folder class are public members of the SuperFolder class. All protected members of the Folder class are protected members of the SuperFolder class. All private members of the Folder class are still members of the SuperFolder class, but they are not available to any of the SuperFolder member functions. They are only accessible through the Folder member functions. Reviewing briefly, public members may be accessed anywhere; protected members may be accessed by member functions of the class and all classes that inherit from it; and private data members are accessible only to the member functions of the class.

  19
  20public:
  21  // Constructor... pass in SuperFolder name
  22  SuperFolder(const string& name);
  23
  24  // Copy constructor
  25  SuperFolder(const SuperFolder& rhs);
  26
  27  // Destructor
  28  ~SuperFolder();
  29
  30  // Assignment operator
  31  SuperFolder& operator=(const SuperFolder& rhs);
  32
  33  // Searches for a Folder object with the same name as folder.  If none
  34  //  exists, folder is added to the list of folders and true is returned.
  35  //  Otherwise, it returns false.
  36  bool add(const Folder& folder); // overloaded method

There is an add function in the Folder class. It still gets inherited (since it has a different prototype). This declaration just overloads the add function so that SuperFolder objects can add TextDoc objects of Folder objects.

  37
  38  // Searches for a folder called name.  If one is found, it removes it
  39  //  from the SuperFolder object and returns true.  Otherwise, it returns
  40  //  false.
  41  bool removeFolder(const string& name);
  42
  43  // Searches for a folder called name.  If one is found, it returns a copy
  44  //  of it.  Otherwise it returns an empty folder.
  45  Folder getFolder(const string& name) const;
  46
  47  // Returns the total number of folders and text documents contained in
  48  //  the SuperFolder object.
  49  unsigned int getNumItems() const; // overridden method
  50
  51  // Returns the number number of bytes required to store the contents of
  52  //  the SuperFolder
  53  unsigned int size() const; // overridden method

The above two member functions (getNumItems and size) are in the base class (Folder). It is important that their function declarations be exactlye the same as in the Folder class, i.e., they have the same name and the same list of formal arguments. These functions cause the SuperFolder class to modify the functionality that was inherited from the Folder class so that it meets the needs of the SuperFolder class. In particular, getNumItems now returns the total number of text documents and folders in the SuperFolder object instead of just the number of text documents, and size now returns the number of bytes needed to store all of the text documents and folders that are part of the SuperFolder object.

  54
  55protected:
  56  // Declared protected because Folder objects must have a name when created
  57  SuperFolder();
  58
  59  list<Folder> folders;
  60};
  61
  62#endif
TextDoc.cpp
   1// TextDoc.cpp
   2// Author: t a y l o r@msoe.edu
   3// Date: 4-18-2002
   4// Purpose: Defines a TextDoc class which represents a text document.
   5
   6#include <string>
   7#include <fstream>
   8#include "TextDoc.h"
   9
  10using std::string;
  11using std::ofstream;
  12
  13// t a y l o r@msoe.edu, 4-18-2002
  14TextDoc::TextDoc(const string& name) : docName(name)
  15{
  16  // Nothing else to do
  17}
  18
  19// t a y l o r@msoe.edu, 4-18-2002
  20TextDoc::TextDoc(const TextDoc& rhs) : docName(rhs.docName),
  21         text(rhs.text)
  22{
  23  // Nothing else to do
  24}
  25
  26// t a y l o r@msoe.edu, 4-18-2002
  27TextDoc::~TextDoc()
  28{
  29  // Nothing to do
  30}
  31
  32// t a y l o r@msoe.edu, 4-18-2002
  33TextDoc& TextDoc::operator=(const TextDoc& rhs)
  34{
  35  if(this!=&rhs) {
  36    docName = rhs.docName;
  37    text = rhs.text;
  38  }
  39  return *this;
  40}
  41
  42// t a y l o r@msoe.edu, 4-18-2002
  43const string& TextDoc::contents() const
  44{
  45  return text;
  46}
  47
  48// t a y l o r@msoe.edu, 4-18-2002
  49string& TextDoc::contents()
  50{
  51  return text;
  52}
  53
  54// t a y l o r@msoe.edu, 4-18-2002
  55const string& TextDoc::getDocName() const
  56{
  57  return docName;
  58}
  59
  60// t a y l o r@msoe.edu, 4-18-2002
  61bool TextDoc::save() const
  62{
  63  bool retVal = false;
  64  ofstream fout(docName.c_str());
  65  if(fout << text) {
  66    retVal = true;
  67  }
  68  return retVal;
  69}
  70
  71// t a y l o r@msoe.edu, 4-18-2002
  72bool TextDoc::saveAs(const string& name)
  73{
  74  docName = name;
  75  return save();
  76}
  77
  78// t a y l o r@msoe.edu, 4-18-2002
  79unsigned int TextDoc::size() const
  80{
  81  return docName.size() + text.length();
  82}
  83
  84// t a y l o r@msoe.edu, 4-18-2002
  85TextDoc::TextDoc()
  86{
  87  // Nothing else to do
  88}
Folder.cpp
   1// Folder.cpp
   2// Author: t a y l o r@msoe.edu
   3// Date: 4-18-2002
   4// Purpose: Defines a Folder class which represents a file system folder
   5//          that stores text documents (TextDoc objects).
   6
   7#include <string>
   8#include <list>
   9#include "Folder.h"
  10
  11using std::string;
  12using std::list;
  13
  14// t a y l o r@msoe.edu, 4-18-2002
  15Folder::Folder(const string& name) : fname(name)
  16{
  17  // Nothing else to do
  18}
  19
  20// t a y l o r@msoe.edu, 4-18-2002
  21Folder::Folder(const Folder& rhs) : fname(rhs.fname), docs(rhs.docs)
  22{
  23  // Nothing else to do
  24}
  25
  26// t a y l o r@msoe.edu, 4-18-2002
  27Folder::~Folder()
  28{
  29  // Nothing to do
  30}
  31
  32// t a y l o r@msoe.edu, 4-18-2002
  33Folder& Folder::operator=(const Folder& rhs)
  34{
  35  if(this!=&rhs) {
  36    fname = rhs.fname;
  37    docs = rhs.docs;
  38  }
  39  return *this;
  40}
  41
  42// t a y l o r@msoe.edu, 4-18-2002
  43const string& Folder::getFolderName() const
  44{
  45  return fname;
  46}
  47
  48// t a y l o r@msoe.edu, 4-18-2002
  49bool Folder::add(const TextDoc& td)
  50{
  51  bool found = false;
  52  std::list<TextDoc>::const_iterator itr = docs.begin();
  53  while(!found && itr!=docs.end()) {
  54    if(td.getDocName() == (*itr).getDocName()) {
  55      found = true;
  56    } else {
  57      ++itr;
  58    }
  59  }
  60  if(!found) {
  61    docs.push_back(td);
  62  }
  63  return !found;
  64}
  65
  66// t a y l o r@msoe.edu, 4-18-2002
  67bool Folder::removeDoc(const string& name)
  68{
  69  bool found = false;
  70  std::list<TextDoc>::iterator itr = docs.begin();
  71  while(itr!=docs.end()) {
  72    if(name == (*itr).getDocName()) {
  73      docs.erase(itr);
  74      found = true;
  75      itr = docs.end();
  76    } else {
  77      ++itr;
  78    }
  79  }
  80  return found;
  81}
  82
  83// t a y l o r@msoe.edu, 4-18-2002
  84TextDoc Folder::getDoc(const string& name) const
  85{
  86  TextDoc retVal("");
  87  std::list<TextDoc>::const_iterator itr = docs.begin();
  88  while(itr!=docs.end() && name != (*itr).getDocName()) {
  89    ++itr;
  90  }
  91  if(itr!=docs.end()) {
  92    retVal = *itr;
  93  }
  94  return retVal;
  95}
  96
  97// t a y l o r@msoe.edu, 4-18-2002
  98unsigned int Folder::getNumItems() const
  99{
 100  return docs.size();
 101}
 102
 103// t a y l o r@msoe.edu, 4-18-2002
 104unsigned int Folder::size() const
 105{
 106  unsigned int bytes = fname.size();
 107  std::list<TextDoc>::const_iterator itr = docs.begin();
 108  while(itr!=docs.end()) {
 109    bytes += (*itr).size();
 110  }
 111  return bytes;
 112}
 113
 114// t a y l o r@msoe.edu, 4-18-2002
 115// Note: this function is declared private
 116Folder::Folder()
 117{
 118  // Nothing else to do
 119}
 120
SuperFolder.cpp
   1// SuperFolder.cpp
   2// Author: t a y l o r@msoe.edu
   3// Date: 4-18-2002
   4// Purpose: Defines a SuperFolder class which represents a file system
   5//          folder that can store text files (TextDoc objects) and
   6//          subfolders (Folder objects).
   7
   8#include <string>
   9#include <list>
  10#include <cassert>
  11#include "SuperFolder.h"
  12
  13using std::string;
  14using std::list;
  15
  16// t a y l o r@msoe.edu, 4-18-2002
  17SuperFolder::SuperFolder(const string& name) : Folder(name)
  18{
  19  // Nothing else to do
  20}

If the initializer list was empty. The default constructor from the Folder class will be called prior to the execution of the SuperFolder constructor. This allows the data members from the Folder class to be initialized properly before the SuperFolder constructor begins.

I have explicitly called the constructor from the Folder class because I want to pass the name to the default constructor for the Folder class.

  21
  22// t a y l o r@msoe.edu, 4-18-2002
  23SuperFolder::SuperFolder(const SuperFolder& rhs) : Folder(rhs), folders(rhs.folders)
  24{
  25  // Nothing else to do
  26}

Here again I have explicitly called the constructor from the Folder class. However, I am calling the copy constructor instead of the default constructor. If you are paying attention, you may be wondering how I can call the copy constructor from the Folder class when rhs is really a reference to a SuperFolder object. It turns out that the compiler will automatically convert an inherited class object into a base class object when necessary.

  27
  28// t a y l o r@msoe.edu, 4-18-2002
  29SuperFolder::~SuperFolder()
  30{
  31  // Nothing to do
  32}
  33
  34// t a y l o r@msoe.edu, 4-18-2002
  35SuperFolder& SuperFolder::operator=(const SuperFolder& rhs)
  36{
  37  if(this!=&rhs) {
  38    Folder::operator=(rhs);

Notice that I have explicitly called the assignment operator from the Folder class. This allows me to rely on the assignment operator from the Folder class to copy all of the data members associated with the Folder class while the rest of the this function copies any additional data members that were defined in the SuperFolder class.

Question: The assignment operator from the Folder class returns a reference to the Folder object. Should I do anything with this or can I ignore what is being passed back?

  39    folders = rhs.folders;
  40  }
  41  return *this;
  42}
  43
  44// t a y l o r@msoe.edu, 4-18-2002
  45bool SuperFolder::add(const Folder& folder)
  46{
  47  bool found = false;
  48  std::list<Folder>::const_iterator itr = folders.begin();
  49  while(!found && itr!=folders.end()) {
  50    if(folder.getFolderName() == (*itr).getFolderName()) {
  51      found = true;
  52    } else {
  53      ++itr;
  54    }
  55  }
  56  if(!found) {
  57    folders.push_back(folder);
  58  }
  59  return !found;
  60}
  61
  62// t a y l o r@msoe.edu, 4-18-2002
  63bool SuperFolder::removeFolder(const string& name)
  64{
  65  bool found = false;
  66  std::list<Folder>::iterator itr = folders.begin();
  67  while(!found && itr!=folders.end()) {
  68    if(name == (*itr).getFolderName()) {
  69      folders.erase(itr);
  70      found = true;
  71    } else {
  72      ++itr;
  73    }
  74  }
  75  return found;
  76}
  77
  78// t a y l o r@msoe.edu, 4-18-2002
  79Folder SuperFolder::getFolder(const string& name) const
  80{
  81  Folder retVal("");
  82  std::list<Folder>::const_iterator itr = folders.begin();
  83  while(itr!=folders.end() && name != (*itr).getFolderName()) {
  84    ++itr;
  85  }
  86  if(itr!=folders.end()) {
  87    retVal = *itr;
  88  }
  89  return retVal;
  90}
  91
  92// t a y l o r@msoe.edu, 4-18-2002
  93unsigned int SuperFolder::getNumItems() const
  94{
  95  return Folder::getNumItems() + folders.size();
  96}

We could have written this as:

     return docs.size() + folders.size();

instead. This would be legal because docs is a protected data member of the Folder class. If it were a private data member, I would need to make use of the getNumItems member function from the Folder class. The method I have implemented is preferred because if changes were made to the Folder::getNumItems(), they would be reflected here, and we wouldn't have to modify this function in order for it to produce the correct answer.

  97
  98// t a y l o r@msoe.edu, 4-18-2002
  99unsigned int SuperFolder::size() const
 100{
 101  unsigned int bytes = Folder::size();
 102  std::list<Folder>::const_iterator itr = folders.begin();
 103  while(itr!=folders.end() && fname != (*itr).getFolderName()) {
 104    bytes += (*itr).size();
 105  }
 106  return bytes;
 107}
 108
 109// t a y l o r@msoe.edu, 4-18-2002
 110SuperFolder::SuperFolder()
 111{
 112  assert(false);
 113}
Copyright   2001 Dr. Christopher C. Taylor t a y l o r@m s o e.e d u Last updated: Fri Jul 19 07:20:01 2002