The changes to class GradeBook
are in the definitions of the constructor (Fig. 3.16, lines 9–12) and setCourseName
(lines 16–29). Rather than using a member initializer, the constructor now calls setCourseName
. In general, all data members should be initialized with member initializers. However, sometimes a constructor must also validate its argument(s)—often, this is handled in the constructor’s body (line 11). The call to setCourseName
validates the constructor’s argument and sets the data member courseName
. Initially, courseName
’s value will be set to the empty string before the constructor’s body executes, then setCourseName
will modify courseName
’s value.
1 // Fig. 3.16: GradeBook.cpp
2 // Implementations of the GradeBook member-function definitions.
3 // The setCourseName function performs validation.
4 #include <iostream>
5 #include "GradeBook.h" // include definition of class GradeBook
6 using namespace std;
7
8 // constructor initializes courseName with string supplied as argument
9 GradeBook::GradeBook( string name )
10 {
11 setCourseName( name ); // validate and store courseName
12 } // end GradeBook constructor
13
14 // function that sets the course name;
15 // ensures that the course name has at most 25 characters
16 void GradeBook::setCourseName( string name )
17 {
18 if ( name.size() <= 25 ) // if name has 25 or fewer characters
19 courseName = name; // store the course name in the object
20
21 if ( name.size() > 25 ) // if name has more than 25 characters
22 {
23 // set courseName to first 25 characters of parameter name
24 courseName = name.substr( 0, 25 ); // start at 0, length of 25
25
26 cerr << "Name "" << name << "" exceeds maximum length (25).
"
27 << "Limiting courseName to first 25 characters.
" << endl;
28 } // end if
29 } // end function setCourseName
30
31 // function to get the course name
32 string GradeBook::getCourseName() const
33 {
34 return courseName; // return object's courseName
35 } // end function getCourseName
36
37 // display a welcome message to the GradeBook user
38 void GradeBook::displayMessage() const
39 {
40 // call getCourseName to get the courseName
41 cout << "Welcome to the grade book for
" << getCourseName()
42 << "!" << endl;
43 } // end function displayMessage
In setCourseName
, the if
statement in lines 18–19 determines whether parameter name
contains a valid course name (i.e., a string
of 25 or fewer characters). If the course name is valid, line 19 stores it in data member courseName
. Note the expression name.size()
in line 18. This is a member-function call just like myGradeBook.displayMessage()
. The C++ Standard Library’s string
class defines a member function size that returns the number of characters in a string
object. Parameter name
is a string
object, so the call name.size()
returns the number of characters in name
. If this value is less than or equal to 25
, name
is valid and line 19 executes.
The if
statement in lines 21–28 handles the case in which setCourseName
receives an invalid course name (i.e., a name that is more than 25 characters long). Even if parameter name
is too long, we still want to leave the GradeBook
object in a consistent state—that is, a state in which the object’s data member courseName
contains a valid value (i.e., a string
of 25 characters or less). Thus, we truncate the specified course name and assign the first 25 characters of name
to the courseName
data member (unfortunately, this could truncate the course name awkwardly). Standard class string
provides member function substr (short for “substring”) that returns a new string
object created by copying part of an existing string
object. The call in line 24 (i.e., name.substr(0, 25)
) passes two integers (0
and 25
) to name
’s member function substr
. These arguments indicate the portion of the string name
that substr
should return. The first argument specifies the starting position in the original string
from which characters are copied—the first character in every string is considered to be at position 0. The second argument specifies the number of characters to copy. Therefore, the call in line 24 returns a 25-character substring of name
starting at position 0 (that is, the first 25 characters in name
). For example, if name
holds the value “CS101 Introduction to Programming in C++”
, substr
returns "CS101 Introduction to Pro"
. After the call to substr
, line 24 assigns the substring returned by substr
to data member courseName
. In this way, setCourseName
ensures that courseName
is always assigned a string containing 25 or fewer characters. If the member function has to truncate the course name to make it valid, lines 26–27 display a warning message using cerr
, as mentioned in Chapter 1.
The if
statement in lines 21–28 contains two body statements—one to set the courseName
to the first 25 characters of parameter name
and one to print an accompanying message to the user. Both statements should execute when name
is too long, so we place them in a pair of braces, { }
. Recall from Chapter 2 that this creates a block. You’ll learn more about placing multiple statements in a control statement’s body in Chapter 4.
The statement in lines 26–27 could also appear without a stream insertion operator at the start of the second line of the statement, as in:
cerr << "Name "" << name << "" exceeds maximum length (25).
"
"Limiting courseName to first 25 characters.
" << endl;
The C++ compiler combines adjacent string literals, even if they appear on separate lines of a program. Thus, in the statement above, the C++ compiler would combine the string literals "" exceeds maximum length (25).
"
and "Limiting courseName to first 25 characters.
"
into a single string literal that produces output identical to that of lines 26–27 in Fig. 3.16. This behavior allows you to print lengthy strings by breaking them across lines in your program without including additional stream insertion operations.