3.4 Account Class: Initializing Objects with Constructors

As mentioned in Section 3.3, when an Account object is created, its string data member name is initialized to the empty string by default —we’ll discuss how that occurs shortly. But what if you want to provide a name when you first create an Account object? Each class can define a constructor that specifies custom initialization for objects of that class. A constructor is a special member function that must have the same name as the class. C++ requires a constructor call when each object is created, so this is the ideal point to initialize an object’s data members.8

Like member functions, a constructor can have parameters—the corresponding argument values help initialize the object’s data members. For example, you can specify an Account object’s name when the object is created, as you’ll do in line 11 of Fig. 3.5:


Account account1{"Jane Green"};

In this case, the string argument "Jane Green" is passed to the Account class’s constructor and used to initialize the name data member of the account1 object. The preceding statement assumes that the Account class has a constructor that takes only a string parameter.

3.4.1 Defining an Account Constructor for Custom Object Initialization

Figure 3.4 shows class Account with a constructor that receives an accountName parameter and uses it to initialize data member name when an Account object is created.

Fig. 3.4 Account class with a constructor that initializes the account name.

Alternate View

 1   // Fig. 3.4: Account.h
 2   // Account class with a constructor that initializes the account name.
 3   #include <string>
 4
 5   class Account {
 6   public:
 7      // constructor initializes data member name with parameter accountName
 8      explicit Account(std::string accountName)     
 9         : name{accountName} { // member initializer
10        // empty body                               
11      }                                             
12
13      // function to set the account name
14      void setName(std::string accountName) {
15         name = accountName;
16      }
17
18      // function to retrieve the account name
19      std::string getName() const {
20         return name;
21      }
22   private:
23      std::string name; // account name data member
24   }; // end class Account

Account Class’s Constructor Definition

Lines 8–11 of Fig. 3.4


explicit Account(std::string accountName)
  : name{accountName} { // member initializer
  // empty body
}

define Account’s constructor. Normally, constructors are public.9

A constructor’s parameter list specifies pieces of data required to initialize an object. Line 8


explicit Account(std::string accountName)

indicates that the constructor has one string parameter called accountName. When you create a new Account object, you must pass a person’s name to the constructor, which will receive that name in the parameter accountName. The constructor will then use accountName to initialize the data member name.

The constructor uses a member-initializer list (line 9)


: name{accountName}

to initialize the name data member with the value of the parameter accountName. Member initializers appear between a constructor’s parameter list and the left brace that begins the constructor’s body. The member initializer list is separated from the parameter list with a colon (:). Each member initializer consists of a data member’s variable name followed by parentheses containing the member’s initial value. In this example, name is initialized with the parameter accountName’s value. If a class contains more than one data member, each member initializer is separated from the next by a comma. The member initializer list executes before the constructor’s body executes.

Performance Tip 3.1

You can perform initialization in the constructor’s body, but you’ll learn in Chapter 9 that it’s more efficient to do it with member initializers, and some types of data members must be initialized this way.

explicit Keyword

We declared this constructor explicit, because it takes a single parameter—this is important for subtle reasons that you’ll learn in Section 10.13. For now, just declare all single-parameter constructors explicit. Line 8 of Fig. 3.4 does not specify a return type, because constructors cannot return values—not even void. Also, constructors cannot be declared const (because initializing an object modifies it).

Using the Same Parameter Name in the Constructor and Member Function setName

Recall from Section 3.3.4 that member function parameters are local variables. In Fig. 3.4, the constructor and member function setName both have a parameter called accountName. Though their identifiers are identical, the parameter in line 8 is a local variable of the constructor that’s not visible to member function setName. Similarly, the parameter in line 14 is a local variable of setName that’s not visible to the constructor. Such visibility is called scope, which is discussed in Section 6.10.

3.4.2 Initializing Account Objects When They’re Created

The AccountTest program (Fig. 3.5) initializes two different Account objects using the constructor. Line 11


Account account1{"Jane Green"};

creates the Account object account1. When you create an object, C++ implicitly calls the class’s constructor to initialize that object. If the constructor has parameters, you place the corresponding arguments in braces, { and }, to the right of the object’s variable name. In line 11, the argument "Jane Green" initializes the new object’s name data member. Line 12


Account account2{"John Blue"};

repeats this process, passing the argument "John Blue" to initialize name for account2. Lines 15–16 use each object’s getName member function to obtain the names and show that they were indeed initialized when the objects were created. The output shows different names, confirming that each Account maintains its own copy of data member name.

Fig. 3.5 Using the Account constructor to initialize the name data member at the time each Account object is created.

Alternate View

 1   // Fig. 3.5: AccountTest.cpp
 2   // Using the Account constructor to initialize the name data
 3   // member at the time each Account object is created.
 4   #include <iostream>
 5   #include "Account.h"
 6
 7   using namespace std;
 8
 9   int main() {
10      // create two Account objects
11      Account account1{"Jane Green"};
12      Account account2{"John Blue"}; 
13
14      // display initial value of name for each Account
15      cout << "account1 name is: " << account1.getName() << endl;
16      cout << "account2 name is: " << account2.getName() << endl;
17   }

account1 name is: Jane Green
account2 name is: John Blue

Default Constructor

Recall that line 10 of Fig. 3.1


Account myAccount;

creates an Account object without placing braces to the right of the object’s variable name. In this case, C++ implicitly calls the class’s default constructor. In any class that does not explicitly define a constructor, the compiler provides a default constructor with no parameters. The default constructor does not initialize the class’s fundamental-type data members, but does call the default constructor for each data member that’s an object of another class. For example, in the Account class of Fig. 3.2, the class’s default constructor calls class string’s default constructor to initialize the data member name to the empty string. An uninitialized fundamental-type variable contains an undefined (“garbage”) value.10

There’s No Default Constructor in a Class That Defines a Constructor

If you define a custom constructor for a class, the compiler will not create a default constructor for that class. In that case, you will not be able to create an Account object using


Account myAccount;

as we did in Fig. 3.1, unless the custom constructor you define has an empty parameter list. We’ll show later that C++11 allows you to force the compiler to create the default constructor even if you’ve defined non-default constructors.

Software Engineering Observation 3.1

Unless default initialization of your class’s data members is acceptable, you should generally provide a custom constructor to ensure that your data members are properly initialized with meaningful values when each new object of your class is created.

3.4.3 Account UML Class Diagram with a Constructor

The UML class diagram of Fig. 3.6 models class Account of Fig. 3.4, which has a constructor with a string accountName parameter. Like operations (Fig. 3.3), the UML models constructors in the third compartment of a class diagram. To distinguish a constructor from the class’s operations, the UML requires that the word “constructor” be enclosed in guillemets (≪ and ≫) and placed before the constructor’s name. It’s customary to list constructors before other operations in the third compartment.

Fig. 3.6 UML class diagram for the Account class of Fig. 3.4.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset