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