Account
Class with a Data Member and Set and Get Member FunctionsNow that we’ve seen class Account
in action (Fig. 3.1), we present class Account
’s details. Then, we present a UML diagram that summarizes class Account
’s attributes and operations in a concise graphical representation.
Account
Class DefinitionClass Account
(Fig. 3.2) contains a name
data member that stores the account holder’s name. A class’s data members maintain data for each object of the class. Later in the chapter, we’ll add a balance
data member to keep track of the money in each Account
. Class Account
also contains member function setName
that a program can call to store a name in an Account
object, and member function getName
that a program can call to obtain a name from an Account
object.
class
and the Class BodyThe class definition begins in line 6:
class Account {
Every class definition contains the keyword class followed immediately by the class’s name—in this case, Account
. Every class’s body is enclosed in an opening left brace (end of line 6) and a closing right brace (line 19). The class definition terminates with a required semicolon (line 19). For reusability, place each class definition in a separate header with the .h
filename extension (Account.h
in this example).
Forgetting the semicolon at the end of a class definition is a syntax error.
Class names, member-function names and data-member names are all identifiers. By convention, variable-name identifiers begin with a lowercase letter, and every word in the name after the first word begins with a capital letter—e.g., firstNumber
starts its second word, Number
, with a capital N
. This naming convention is known as camel case, because the uppercase letters stand out like a camel’s humps. Also by convention, class names begin with an initial uppercase letter, and member-function and data-member names begin with an initial lowercase letter.
name
of Type string
Recall from Section 1.8 that an object has attributes, implemented as data members. The object carries these with it throughout its lifetime. Each object has its own copy of the class’s data members. Normally, a class also contains one or more member functions. These manipulate the data members belonging to particular objects of the class. The data members exist
before a program calls member functions on an object,
while the member functions are executing and
after the member functions complete execution.
Data members are declared inside a class definition but outside the bodies of the class’s member functions. Line 18
std::string name; // data member containing account holder’s name
declares data member name
of type string
. If there are many Account
objects, each has its own name
. Because name
is a data member, it can be manipulated by each of the class’s member functions. The default value for a string
is the empty string (i.e., ""
)—this is why line 13 in main
(Fig. 3.1) did not display a name the first time we called myAccount
’s getName
member function. Section 3.4 explains how a string
receives its default value.
By convention, place a class’s data members last in the class’s body. You can list the class’s data members anywhere in the class outside its member-function definitions, but scattering the data members can lead to hard-to-read code.
std::
with Standard Library Components in HeadersThroughout the Account.h
header (Fig. 3.2), we use std::
when referring to string
(lines 9, 14 and 18). For subtle reasons that we explain in Section 23.4, headers should not contain using
directives or using
declarations.
setName
Member FunctionLet’s walk through the code of member function setName
’s definition (lines 9–11):
void setName(std::string accountName) {
name = accountName; // store the name
}
We refer to the first line of each function definition (line 9) as the function header. The member function’s return type (which appears to the left of the function’s name) specifies the type of data the member function returns to its caller after performing its task. The return type void (line 9) indicates that when setName
completes its task, it does not return (i.e., give back) any information to its calling function —in this example, line 19 of the main
function (Fig. 3.1). As you’ll soon see, Account
member function getName
does return a value.
setName
ParameterOur car analogy from Section 1.8 mentioned that pressing a car’s gas pedal sends a message to the car to perform a task—make the car go faster. But how fast should the car accelerate? The farther down you press the pedal, the faster the car accelerates. So the message to the car includes both the task to perform and information that helps the car perform that task. This information is known as a parameter —the parameter’s value helps the car determine how fast to accelerate. Similarly, a member function can require one or more parameters that represent the data it needs to perform its task.
Member function setName
declares the string
parameter accountName
—which receives the name that’s passed to setName
as an argument. When line 19 in Fig. 3.1
myAccount.setName(theName); // put theName in myAccount
executes, the argument value in the call’s parentheses (i.e., the value stored in theName
) is copied into the corresponding parameter (accountName
) in the member function’s header (line 9 of Fig. 3.2). In Fig. 3.1’s sample execution, we entered "Jane
Green"
for theName
, so "Jane
Green"
was copied into the accountName
parameter.
setName
Parameter ListParameters like accountName
are declared in a parameter list located in the required parentheses following the member function’s name. Each parameter must specify a type (e.g., string
) followed by a parameter name (e.g., accountName
). When there are multiple parameters, each is separated from the next by a comma, as in
(type1 name1, type2 name2, …)
The number and order of arguments in a function call must match the number and order of parameters in the function definition’s parameter list.
setName
Member Function BodyEvery member function body is delimited by an opening left brace (end of line 9 of Fig. 3.2) and a closing right brace (line 11). Within the braces are one or more statements that perform the member function’s task(s). In this case, the member function body contains a single statement (line 10)
name = accountName; // store the account name
that assigns the accountName
parameter’s value (a string
) to the class’s name
data member, thus storing the account name in the object for which setName
was called— myAccount
in this example’s main
program.6 After line 10 executes, program execution reaches the member function’s closing brace (line 11), so the function returns to its caller.
In Chapter 2, we declared all of a program’s variables in the main
function. Variables declared in a particular function’s body are local variables which can be used only in that function. When a function terminates, the values of its local variables are lost. A function’s parameters also are local variables of that function.
The argument types in the member function call must be consistent with the types of the corresponding parameters in the member function’s definition. (As you’ll see in Chapter 6, Functions and an Introduction to Recursion, an argument’s type and its corresponding parameter’s type are not required to be identical.) In our example, the member function call passes one argument of type string
(theName
)—and the member function definition specifies one parameter of type string
(accountName
). So in this example, the type of the argument in the member function call happens to exactly match the type of the parameter in the member function header.
getName
Member FunctionMember function getName
(lines 14–16)
std::string getName() const {
return name; // return name’s value to this function’s caller
}
returns a particular Account
object’s name
to the caller—a string
, as specified by the function’s return type. The member function has an empty parameter list, so it does not require additional information to perform its task. When a member function with a return type other than void
is called and completes its task, it must return a result to its caller. A statement that calls member function getName
on an Account
object expects to receive the Account
’s name.
The return statement in line 15
return name; // return name’s value to this function’s caller
passes the string
value of data member name
back to the caller, which then can use the returned value. For example, the statement in lines 22–23 of Fig. 3.1
cout << "Name in object myAccount is: "
<< myAccount.getName() << endl;
uses the value returned by getName
to output the name stored in the myAccount
object.
const
Member FunctionsWe declared member function getName
as const in line 14 of Fig. 3.2
std::string getName() const {
because in the process of returning the name
the function does not, and should not, modify the Account
object on which it’s called.
Declaring a member function with const
to the right of the parameter list tells the compiler, “this function should not modify the object on which it’s called—if it does, please issue a compilation error.” This can help you locate errors if you accidentally insert in the member function code that would modify the object.
private
and public
The keyword private (line 17)
private:
is an access specifier. Access specifiers are always followed by a colon (:
). Data member name
’s declaration (line 18) appears after access specifier private:
to indicate that name
is accessible only to class Account
’s member functions.7 This is known as data hiding —the data member name
is encapsulated (hidden) and can be used only in class Account
’s setName
and getName
member functions. Most data-member declarations appear after the private:
access specifier. For the remainder of the text, when we refer to the access specifiers private
and public
in the text, we’ll often omit the colon as we did in this sentence.
This class also contains the public access specifier (line 7)
public:
Data members or member functions listed after access specifier public
(and before the next access specifier if there is one) are “available to the public.” They can be used by other functions in the program (such as main
), and by member functions of other classes (if there are any). In Chapter 11, we’ll introduce the protected
access specifier.
By default, everything in a class is private
, unless you specify otherwise. Once you list an access specifier, everything from that point has that access until you list another access specifier. We prefer to list public
only once, grouping everything that’s public
, and we prefer to list private
only once, grouping everything that’s private
. The access specifiers public
and private
may be repeated, but this is unnecessary and can be confusing.
Making a class’s data members private
and member functions public
facilitates debugging because problems with data manipulations are localized to the member functions.
An attempt by a function that’s not a member of a particular class to access a private
member of that class is a compilation error.
Account
UML Class DiagramWe’ll often use UML class diagrams to summarize a class’s attributes and operations. In industry, UML diagrams help systems designers specify systems in a concise, graphical, programming-language-independent manner, before programmers implement the systems in specific programming languages. Figure 3.3 presents a UML class diagram for class Account
of Fig. 3.2.
In the UML, each class is modeled in a class diagram as a rectangle with three compartments. In this diagram the top compartment contains the class name Account
centered horizontally in boldface type.
The middle compartment contains the class’s attribute name
, which corresponds to the data member of the same name in C++. Data member name
is private
in C++, so the UML class diagram lists a minus sign (–) access modifier before the attribute name. Following the attribute name are a colon and the attribute type, in this case string
.
The bottom compartment contains the class’s operations, setName
and getName
, which correspond to the member functions of the same names in C++. The UML models operations by listing the operation name preceded by an access modifier, in this case + setName
. This plus sign (+
) indicates that setName
is a public operation in the UML (because it’s a public
member function in C++). Operation getName
is also a public operation.
The UML indicates the return type of an operation by placing a colon and the return type after the parentheses following the operation name. Account
member function setName
does not return a value (because it returns void
in C++), so the UML class diagram does not specify a return type after the parentheses of this operation. Member function getName
has a string
return type.
The UML models a parameter by listing the parameter name, followed by a colon and the parameter type in the parentheses after the operation name. The UML has its own data types similar to those of C++—for simplicity, we use the C++ types. Account
member function setName
has a string
parameter called accountName
, so the class diagram lists accountName : string
between the parentheses following the member function name. Operation getName
does not have any parameters, so the parentheses following the operation name in the class diagram are empty, just as they are in the member function’s definition in line 14 of Fig. 3.2.