Previous Page TOC Next Page



- Project 11 -
Inheritance and Virtual Functions


In this lesson, you learned about the advanced features of Visual C++. You learned how to make one class out of another and how to change the way a function is called to depend on either the calling type or the object type.

In this lesson, you saw the following:

Project 11 Listing. An object-oriented pet care program.


  1:// File name : PROJCT11.CPP

  2:// Object oriented pet program to manage

  3:// a simple list of different types of

  4:// pets

  5://

  6:#include <iostream.h>

  7:#include <string.h>

  8:

  9://------------------------------------------------------------

 10:// Pet class

 11://

 12:class Pet

 13:  {

 14:    public:

 15:      virtual ~Pet()              // Destructor

 16:        {

 17:          delete [] name;

 18:        }

 19:      void Print() const;         // Print all about pet

 20:      void Query();               // Get details

 21:      const char * GetName() const// Provide name string

 22:        {

 23:          if (name)

 24:            return name;

 25:          else

 26:            return "";

 27:        }

 28:    protected:

 29:      virtual void PrintDetails() const = 0;// Print details

 30:      virtual void QueryDetails() = 0;      // Ask for details

 31:      virtual const char * GetPetType() const = 0;

 32:      Pet()     // protected -

 33:                // do not make Pets

 34:        {

 35:          name = 0;

 36:        }

 37:    private:

 38:      char * name;

 39:  };

 40:void Pet::Print() const

 41:  {

 42:    cout << GetPetType()  << " : ";

 43:    if (name)

 44:      cout << name << " - ";

 45:    PrintDetails();

 46:    cout << endl;

 47:  }

 48:

 49:void Pet::Query()

 50:  {

 51:    char tempName[81];

 52:    cout << "What is your pet " << GetPetType() <<"'s name? ";

 53:    cin.getline(tempName,81);

 54:    if (name)

 55:      delete [] name;

 56:    name = new char[strlen(tempName) + 1];

 57:    strcpy(name,tempName);

 58:    QueryDetails();

 59:  }

 60:

 61://------------------------------------------------------------

 62:// Cat class - derived from Pet

 63://

 64:class Cat : public Pet

 65:  {

 66:    public:

 67:      Cat(int Scratches = 1)

 68:        {

 69:          scratches = Scratches;

 70:        }

 71:    protected:

 72:      virtual void PrintDetails() const;

 73:      virtual void QueryDetails();

 74:      const char * GetPetType() const

 75:        {

 76:          return "Cat";

 77:        }

 78:    private:

 79:      int scratches;

 80:  };

 81:

 82:void Cat::PrintDetails() const

 83:  {

 84:    cout << "Scratches: " << (scratches? "Yes":"No");

 85:  }

 86:

 87:void Cat::QueryDetails()

 88:  {

 89:    char yn;

 90:    cout << "Does your cat " << GetName() << " scratch? ";

 91:    cin >> yn;

 92:    cin.ignore(80,'\n');

 93:    if (yn == 'Y' || yn == 'y')

 94:      scratches = 1;

 95:    else

 96:      scratches = 0;

 97:  }

 98:

 99://------------------------------------------------------------

100:// Dog class - derived from Pet

101://

102:

103:class Dog : public Pet

104:  {

105:    public:

106:      Dog(int Barks = 1)

107:        {

108:          barks = Barks;

109:        }

110:    protected:

111:      virtual void PrintDetails() const;

112:      virtual void QueryDetails();

113:      const char * GetPetType() const

114:        {

115:          return "Dog";

116:        }

117:    private:

118:      int barks;

119:  };

120:

121:void Dog::PrintDetails() const

122:  {

123:    cout << "Barks: " << (barks? "Yes":"No");

124:  }

125:

126:void Dog::QueryDetails()

127:  {

128:    char yn;

129:    cout << "Does your dog " << GetName() << " bark? ";

130:    cin >> yn;

131:    cin.ignore(80,'\n');

132:    if (yn == 'Y' || yn == 'y')

133:      barks = 1;

134:    else

135:      barks = 0;

136:  }

137:

138://------------------------------------------------------------

139:// Fish class - derived from Pet

140://

141:class Fish : public Pet

142:  {

143:    public:

144:      Fish(int ColdWater = 0)

145:        {

146:          coldWater = ColdWater;

147:        }

148:    protected:

149:      virtual void PrintDetails() const;

150:      virtual void QueryDetails();

151:      const char * GetPetType() const

152:        {

153:          return "Fish";

154:        }

155:    private:

156:      int coldWater;

157:  };

158:void Fish::PrintDetails() const

159:  {

160:    cout << (coldWater? "Cold water":"Tropical");

161:  }

162:

163:void Fish::QueryDetails()

164:  {

165:    char yn;

166:    cout << "Is your fish " << GetName() << " tropical? ";

167:    cin >> yn;

168:    cin.ignore(80,'\n');

169:    if (yn == 'Y' || yn == 'y')

170:      coldWater = 0;

171:    else

172:      coldWater = 1;

173:  }

174:

175://------------------------------------------------------------

176:// main procedure

177://

178:

179:void main()

180:  {

181:     const int maxPets = 20;

182:     char type = ' ';

183:     Pet * pets[maxPets] = {0};

184:     int count = 0;

185:

186:     while (count < maxPets)

187:       {

188:         // Where do you want to go today?

189:         cout << "Pet type, [C]at, [D]og, [F]ish, [Q]uit: ";

190:         cin >> type;

191:         cin.ignore(80,'\n');

192:

193:         // Stop loop early

194:         if (type == 'q' || type == 'Q')

195:           break;

196:

197:         switch (type)

198:           {

199:             case 'C': // Cat

200:             case 'c':

201:               {

202:                 pets[count] = new Cat;

203:                 break;

204:               }

205:             case 'D': // Dog

206:             case 'd':

207:               {

208:                 pets[count] = new Dog;

209:                 break;

210:               }

211:             case 'F': // Fish

212:             case 'f':

213:               {

214:                 pets[count] = new Fish;

215:                 break;

216:               }

217:             default:

218:               continue; // can be used in switch

219:          }

220:        pets[count]->Query();

221:        count++;

222:      }

223:

224:   // List pets - don't need derived classes for this

225:    cout << endl << "Pet Names" << endl;

226:    for (int i = 0; i < count; i++)

227:      {

228:        cout << pets[i]->GetName();

229:        cout << endl;

230:      }

231:

232:    // Print characteristics - rely on virtual functions

233:    cout << endl << "Characteristics" << endl;

234:    for (i = 0; i < count; i++)

235:      pets[i]->Print();

236:

237:    // Tidy up storage

238:    for (i = 0; i < count; i++)

239:      delete pets[i];

240:  }

OUTPUT

Description

1: Comment refers to the source filename.

2: Comment to describe the program.

3: The program description continues.

4: The program description continues.

5: Blank lines help to make the program more readable.

6: Include the header for the library of stream output functions.

7: Include the header for the library of string handling functions.

8: Blank lines help to make the program more readable.

9: A comment helps separate the different classes.

10: A title for the following class.

11: A blank comment can also be used for appearance.

12: A line to declare a class called Pet.

13: All classes start with an opening brace.

14: All members after this label will be declared public.

15: The destructor for Pet is shown with the ~ character. It is declared virtual.

16: The destructor function is coded inline. The function starts with an opening brace.

17: Delete the character string pointed to by name.

18: All functions end with a closing brace.

19: A function Print() is declared that will not change the class members.

20: A function Query() is declared. This is allowed to change class members.

21: A function GetName() is declared that will not change class members.

22: All functions start with opening braces. This is declared inline.

23: name might not have a string attached, but the constructor ensures it is zeroed.

24: If name did have a string, return it.

25: A single statement if-else does not need braces surrounding the statement.

26: Return a blank string if no name has been set.

27: A closing brace ends all functions.

28: All members following this label will be protected.

29: This virtual function has not been defined and is known as a pure virtual function.

30: QueryDetails() is also a pure virtual function.

31: There is no definition for GetPetType().

32: The default constructor for the Pet class.

33: A comment helps explain an unusual coding feature.

34: An inline function starts with a closing brace.

35: Pointers should always be initialized. A valid pointer can never be zero.

36: Functions always end with closing braces.

37: All members following this label will be private.

38: A pointer to a character string initially does not own any storage.

39: All class declarations end with both a closing brace and a semicolon.

40: The function Print() belonging to the Pet class is defined.

41: All functions start with an opening brace.

42: Output the type of pet, using a virtual function so that each class can output its name.

43: Check the validity of a character pointer before using.

44: name is a member of this class, so it needs no special function to access it.

45: Call a virtual function to get details that differ by derived type.

46: Output a newline sequence.

47: All functions end with a closing brace.

48: Blank lines help you make the code more readable.

49: Define the nonvirtual function Query.

50: All functions start with an opening brace.

51: Declare a temporary character string much bigger than expected input.

52: Ask for user input, using a virtual function to customize the request for each class.

53: Get the name into a temporary string.

54: If the name already points at a string, delete it.

55: Delete the current string to recover the memory.

56: Create a dynamic memory allocation just big enough to hold the string and its terminator.

57: Copy the temporary name into the class storage.

58: Call a virtual function to get details specific to the actual class.

59: All functions end with a closing brace.

60: Blank lines help to make the program more readable.

61: A comment to mark the start of a new class.

62: A comment to identify which class is now being defined.

63: Empty comments can enhance the appearance of the program.

64: Class Cat builds the functionality of class Pet.

65: Class definitions start with an opening brace.

66: All members following this label will be public.

67: The constructor for cat can optionally take a parameter.

68: A function always starts with an opening brace.

69: A constructor should always initialize the members.

70: A function always ends with a closing brace.

71: All the functions following this label will be protected.

72: This class is going to define the PrintDetails() function.

73: This class is going to define the QueryDetails() function.

74: This class defines the GetPetType() function.

75: All functions start with an opening brace.

76: This function returns the literal string Cat.

77: All functions end with a closing brace.

78: All members following this label will be private.

79: A private data member that is an integer.

80: All class definitions end with a closing brace and a semicolon.

81: Blank lines make the program more readable.

82: Define the function PrintDetails(). This version belongs to Cat.

83: All functions start with an opening brace.

84: Output extra details of Cat class.

85: All functions end with a closing brace.

86: Blank lines help to make the program more readable.

87: Define the function QueryDetails().

88: All functions start with an opening brace.

89: Declare a character variable to test the input.

90: Query the user for information. Customize the output with a call for base class information.

91: Ask for an answer that takes just the first character.

92: Ignore the input up until the newline character.

93: If the answer is yes. . .

94: Set the member flag to true.

95: If the answer is no. . .

96: Set the member flag to false.

97: All functions end with a closing brace.

98: Blank lines help to make the program more readable.

99: A comment to mark the start of a new class.

100: A comment to identify which class is now being defined.

101: Empty comments can enhance the appearance of the program.

102: Blank lines help to make the program more readable.

103: Class Dog builds the functionality of class Pet.

104: Class definitions start with an opening brace.

105: All members following this label will be public.

106: The constructor for Dog can optionally take a parameter.

107: A function always starts with an opening brace.

108: A constructor should always initialize the members.

109: A function always ends with a closing brace.

110: All functions following this label will be protected.

111: This class is going to define the PrintDetails() function.

112: This class is going to define the QueryDetails() function.

113: This class defines the GetPetType() function.

114: All functions start with an opening brace.

115: This function returns the literal string Dog.

116: All functions end with a closing brace.

117: All members following this label will be private.

118: A private data member that is an integer.

119: All class definitions end with a closing brace and a semicolon.

120: Blank lines make the program more readable.

121: Define the function PrintDetails(). This version belongs to Cat.

122: All functions start with an opening brace.

123: Output extra details of Dog class.

124: All functions end with a closing brace.

125: Blank lines help to make the program more readable.

126: Define the function QueryDetails().

127: All functions start with an opening brace.

128: Declare a character variable to test the input.

129: Query the user for information. Customize the output with a call for base class information.

130: Ask for an answer that takes just the first character.

131: Ignore the input up until the newline character.

132: If the answer is yes. . .

133: Set the member flag to true.

134: If the answer is no. . .

135: Set the member flag to false.

136: All functions end with a closing brace.

137: Blank lines help to make the program more readable.

138: A comment to mark the start of a new class.

139: A comment to identify which class is now being defined.

140: Empty comments can enhance the appearance of the program.

141: Class Fish builds the functionality of class Pet.

142: Class definitions start with an opening brace.

143: All members following this label will be public.

144: The constructor for Fish can optionally take a parameter.

145: A function always starts with an opening brace.

146: A constructor should always initialize the members.

147: A function always ends with a closing brace.

148: All the functions following this label will be protected.

149: This class is going to define the PrintDetails() function.

150: This class is going to define the QueryDetails() function.

151: This class defines the GetPetType() function.

152: All functions start with an opening brace.

153: This function returns the literal string Fish.

154: All functions end with a closing brace.

155: All members following this label will be private.

156: A private data member that is an integer.

157: All class definitions end with a closing brace and a semicolon.

158: Define the function PrintDetails(). This version belongs to Fish.

159: All functions start with an opening brace.

160: Output extra details of Cat class.

161: All functions end with a closing brace.

162: Blank lines help to make the program more readable.

163: Define the function QueryDetails().

164: All functions start with an opening brace.

165: Declare a character variable to test the input.

166: Query the user for information. Customize the output with a call for base class information.

167: Ask for an answer that takes just the first character.

168: Ignore the input up until the newline character.

169: If the answer is yes. . .

170: Set the member flag to true.

171: If the answer is no. . .

172: Set the member flag to false.

173: All functions end with a closing brace.

174: Blank lines make the program more readable.

175: A comment to divide the code.

176: A comment to tell the programmer that he has found the main procedure.

177: Blank comments can enhance the appearance of the program.

178: Blank lines make the program more readable.

179: The start of the main procedure.

180: All functions start with an opening brace.

181: Define a constant for the maximum number of entries.

182: Initialize a temporary input character.

183: Define an array of pointers to the Pet class.

184: A counter to record how many pets have been entered.

185: Blank lines make the program more readable.

186: Do the following statements as long as the number of entries do not exceed the array capacity.

187: A while loop of multiple statements is delimited by an opening brace.

188: Not all comments serve a useful purpose.

189: Prompt the user for a selection.

190: Store the first character of a users answer.

191: Ignore any spare input after the first character.

192: Blank lines make the program more readable.

193: Comments can explain why code is written.

194: Test the input to see whether the user has finished.

195: Leave the loop if the if test is true.

196: Blank lines make the program more readable.

197: Avoid complex if statements by using the switch statement.

198: switch statements are enclosed in braces.

199: Execute from here if type is 'C'.

200: Execute from here if type is 'c'. The first case will fall through.

201: case statements can be enclosed in a block.

202: Make an object of type Cat and store it in a general Pet pointer.

203: Break out of the rest of the switch statement.

204: End of case block.

205: case for Dog.

206: case for Dog.

207: case statements can be enclosed in a block.

208: Make an object of type Dog and store it in a general Pet pointer.

209: Break out of the rest of the switch statement.

210: End of case block.

211: case for Fish

212: case for Fish

213: case statements can be enclosed in a block.

214: Make an object of type Fish and store it in a general Pet pointer.

215: Break out of the rest of the switch statement.

216: End of case block.

217: If the input does not match any planned case, do the following.

218: Executing continue will go around the loop, skipping the remaining code.

219: End the switch statement.

220: Call the input function for the new object. Because it contains virtual function calls, different code for each type will be called.

221: Increment the number of valid objects count.

222: End the while loop compound statement.

223: Blank lines help make the program more readable.

224: Comment to help understand the following processing.

225: Output a title.

226: for as many items in the container.

227: for loops performing multiple statements enclose them in braces.

228: Output the pet's name by using a nonvirtual function belonging to the base class.

229: A newline character sequence is output.

230: End of the for loop is denoted by the closing brace.

231: Blank lines make the program more readable.

232: A comment to explain the following processing.

233: Output a title.

234: for all the items in the container.

235: A for loop can execute a single statement.

236: Blank lines make the code more readable.

237: A comment to explain the following processing.

238: for each item in the container.

239: Delete the storage associated with the pointer.

240: The main function ends with a closing brace.



29: Classes containing pure virtual functions are known as abstract classes.

69: If no base constructor is explicitly called in the initialization list, the default base constructor is called.

71: Protected members are only visible to this class and derived classes.

76: Visual C++ can't access the actual class name.

183: An array of pointers takes up a small amount of space compared to the classes, and derived classes might take up much more storage than a base class.

201: case statements must be enclosed in braces if they declare a variable.

203: Meeting a case statement does not cause a branch out of the switch statement.

226: The scope of local variable i is the block containing for, not the for loop itself. Note the following for loops.

235: Print() contains virtual functions that will execute code specific to each object's class.

239: Because the base class destructor is virtual, the correct destructor will be called even though the pointer belongs to the base class.


Previous Page Page Top TOC Next Page