Initializing Objects with Constructors

As mentioned in Section 3.6, when an object of class GradeBook (Fig. 3.5) is created, its data member courseName is initialized to the empty string by default. What if you want to provide a course name when you create a GradeBook object? Each class you declare can provide a constructor that can be used to initialize an object of the class when the object is created. A constructor is a special member function that must be defined with the same name as the class, so that the compiler can distinguish it from the class's other member functions. An important difference between constructors and other functions is that constructors cannot return values, so they cannot specify a return type (not even void). Normally, constructors are declared public. The term "constructor" is often abbreviated as "ctor" in the literaturewe prefer not to use this abbreviation.

C++ requires a constructor call for each object that is created, which helps ensure that the object is initialized properly before it is used in a programthe constructor call occurs implicitly when the object is created. In any class that does not explicitly include a constructor, the compiler provides a default constructorthat is, a constructor with no parameters. For example, when line 46 of Fig. 3.5 creates a GradeBook object, the default constructor is called, because the declaration of myGradeBook does not specify any constructor arguments. The default constructor provided by the compiler creates a GradeBook object without giving any initial values to the object's data members. [ Note: For data members that are objects of other classes, the default constructor implicitly calls each data member's default constructor to ensure that the data member is initialized properly. In fact, this is why the string data member courseName (in Fig. 3.5) was initialized to the empty stringthe default constructor for class string sets the string's value to the empty string. In Section 10.3, you will learn more about initializing data members that are objects of other classes.]


In the example of Fig. 3.7, we specify a course name for a GradeBook object when the object is created (line 49). In this case, the argument "CS101 Introduction to C++ Programming" is passed to the GradeBook object's constructor (lines 1720) and used to initialize the courseName. Figure 3.7 defines a modified GradeBook class containing a constructor with a string parameter that receives the initial course name.

Figure 3.7. Instantiating multiple objects of the GradeBook class and using the GradeBook constructor to specify the course name when each GradeBook object is created.

(This item is displayed on pages 92 - 93 in the print version)

1 // Fig. 3.7: fig03_07.cpp 2 // Instantiating multiple objects of the GradeBook class and using 3 // the GradeBook constructor to specify the course name 4 // when each GradeBook object is created. 5 #include 6 using std::cout; 7 using std::endl; 8 9 #include // program uses C++ standard string class 10 using std::string; 11 12 // GradeBook class definition 13 class GradeBook 14 { 15 public: 16 // constructor initializes courseName with string supplied as argument 17 GradeBook( string name ) 18 { 19 setCourseName( name ); // call set function to initialize courseName 20 } // end GradeBook constructor 21 22 // function to set the course name 23 void setCourseName( string name ) 24 { 25 courseName = name; // store the course name in the object 26 } // end function setCourseName 27 28 // function to get the course name 29 string getCourseName() 30 { 31 return courseName; // return object's courseName 32 } // end function getCourseName 33 34 // display a welcome message to the GradeBook user 35 void displayMessage() 36 { 37 // call getCourseName to get the courseName 38 cout << "Welcome to the grade book for " << getCourseName() 39 << "!" << endl; 40 } // end function displayMessage 41 private: 42 string courseName; // course name for this GradeBook 43 }; // end class GradeBook 44 45 // function main begins program execution 46 int main() 47 { 48 // create two GradeBook objects 49 GradeBook gradeBook1( "CS101 Introduction to C++ Programming" ); 50 GradeBook gradeBook2( "CS102 Data Structures in C++" ); 51 52 // display initial value of courseName for each GradeBook 53 cout << "gradeBook1 created for course: " << gradeBook1.getCourseName() 54 << " gradeBook2 created for course: " << gradeBook2.getCourseName() 55 << endl; 56 return 0; // indicate successful termination 57 } // end main  

gradeBook1 created for course: CS101 Introduction to C++ Programming gradeBook2 created for course: CS102 Data Structures in C++  


Defining a Constructor

Lines 1720 of Fig. 3.7 define a constructor for class GradeBook. Notice that the constructor has the same name as its class, GradeBook. A constructor specifies in its parameter list the data it requires to perform its task. When you create a new object, you place this data in the parentheses that follow the object name (as we did in lines 4950). Line 17 indicates that class GradeBook's constructor has a string parameter called name. Note that line 17 does not specify a return type, because constructors cannot return values (or even void).

Line 19 in the constructor's body passes the constructor's parameter name to member function setCourseName, which assigns a value to data member courseName. The setCourseName member function (lines 2326) simply assigns its parameter name to the data member courseName, so you might be wondering why we bother making the call to setCourseName in line 19the constructor certainly could perform the assignment courseName = name. In Section 3.10, we modify setCourseName to perform validation (ensuring that, in this case, the courseName is 25 or fewer characters in length). At that point the benefits of calling setCourseName from the constructor will become clear. Note that both the constructor (line 17) and the setCourseName function (line 23) use a parameter called name. You can use the same parameter names in different functions because the parameters are local to each function; they do not interfere with one another.


Testing Class GradeBook

Lines 4657 of Fig. 3.7 define the main function that tests class GradeBook and demonstrates initializing GradeBook objects using a constructor. Line 49 in function main creates and initializes a GradeBook object called gradeBook1. When this line executes, the GradeBook constructor (lines 1720) is called (implicitly by C++) with the argument "CS101 Introduction to C++ Programming" to initialize gradeBook1's course name. Line 50 repeats this process for the GradeBook object called gradeBook2, this time passing the argument "CS102 Data Structures in C++" to initialize gradeBook2's course name. Lines 5354 use each object's getCourseName member function to obtain the course names and show that they were indeed initialized when the objects were created. The output confirms that each GradeBook object maintains its own copy of data member courseName.

Two Ways to Provide a Default Constructor for a Class

Any constructor that takes no arguments is called a default constructor. A class gets a default constructor in one of two ways:

  1. The compiler implicitly creates a default constructor in a class that does not define a constructor. Such a default constructor does not initialize the class's data members, but does call the default constructor for each data member that is an object of another class. [Note: An uninitialized variable typically contains a "garbage" value (e.g., an uninitialized int variable might contain -858993460, which is likely to be an incorrect value for that variable in most programs).]
  2. The programmer explicitly defines a constructor that takes no arguments. Such a default constructor will perform the initialization specified by the programmer and will call the default constructor for each data member that is an object of another class.

If the programmer defines a constructor with arguments, C++ will not implicitly create a default constructor for that class. Note that for each version of class GradeBook in Fig. 3.1, Fig. 3.3 and Fig. 3.5 the compiler implicitly defined a default constructor.

Error-Prevention Tip 3.2

Unless no initialization of your class's data members is necessary (almost never), provide a constructor to ensure that your class's data members are initialized with meaningful values when each new object of your class is created.

Software Engineering Observation 3.5

Data members can be initialized in a constructor of the class or their values may be set later after the object is created. However, it is a good software engineering practice to ensure that an object is fully initialized before the client code invokes the object's member functions. In general, you should not rely on the client code to ensure that an object gets initialized properly.

 

Adding the Constructor to Class GradeBook's UML Class Diagram

The UML class diagram of Fig. 3.8 models class GradeBook of Fig. 3.7, which has a constructor with a name parameter of type string (represented by type String in the UML). Like operations, the UML models constructors in the third compartment of a class in a class diagram. To distinguish a constructor from a class's operations, the UML places the word "constructor" between guillemets (« and ») before the constructor's name. It is customary to list the class's constructor before other operations in the third compartment.


Figure 3.8. UML class diagram indicating that class GradeBook has a constructor with a name parameter of UML type String.

Категории