Account
Class: Initializing Objects with ConstructorsAs 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.
Account
Constructor for Custom Object InitializationFigure 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.
Account
Class’s Constructor DefinitionLines 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.
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
KeywordWe 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).
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.
Account
Objects When They’re CreatedThe 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
.
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
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.
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.
Account
UML Class Diagram with a ConstructorThe 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.