As we said in Chapter 6, an object is a variable that has member functions, and a class is a data type whose variables are objects. Thus, the definition of a class should be a data type definition that describes two things: (1) what kinds of values the variables can hold and (2) what the member functions are. We will approach class definitions in two steps. We will first tell you how to give a type definition for a structure. A structure (of the kind discussed here) can be thought of as an object without any member functions. After you learn about structures, it will be a natural extension to define classes.
Sometimes it is useful to have a collection of values of different types and to treat the collection as a single item. For example, consider a bank certificate of deposit, which is often called a CD. A CD is a bank account that does not allow withdrawals for a specified number of months. A CD naturally has three pieces of data associated with it: the account balance, the interest rate for the account, and the term, which is the number of months until maturity. The first two items can be represented as values of type double
, and the number of months can be represented as a value of type int
. Display 10.1 shows the definition of a structure called CDAccount
that can be used for this kind of account. The definition is embedded in a complete program that demonstrates this structure type definition. As you can see from the sample dialogue, this particular bank specializes in short-term CDs, so the term will always be 12 or fewer months. Let’s look at how this sample structure is defined and used.
1 //Program to demonstrate the CDAccount structure type.
2 #include <iostream>
3 using namespace std;
4 //Structure for a bank certificate of deposit:
5 struct CDAccount
6 {
7 double balance;
8 double interestRate;
9 int term; //months until maturity
10 };
11
12
13 void getData(CDAccount& theAccount);
14 //Postcondition: theAccount.balance and theAccount.interestRate
15 //have been given values that the user entered at the keyboard.
16
17
18 int main( )
19 {
20 CDAccount account;
21 getData(account);
22
23 double rateFraction, interest;
24 rateFraction = account.interestRate / 100.0;
25 interest = account.balance * rateFraction * (account.term / 12.0);
26 account.balance = account.balance + interest;
27
28 cout.setf(ios::fixed);
29 cout.setf(ios::showpoint);
30 cout.precision(2);
31 cout << "When your CD matures in "
32 << account.term << " months,\n"
33 << "it will have a balance of $"
34 << account.balance << endl;
35 return 0;
36 }
37
38 //Uses iostream:
39 void getData(CDAccount& theAccount)
40 {
41 cout << "Enter account balance: $";
42 cin >> theAccount.balance;
43 cout << "Enter account interest rate: ";
44 cin >> theAccount.interestRate;
45 cout << "Enter the number of months until maturity\n"
46 << "(must be 12 or fewer months): ";
47 cin >> theAccount.term;
48 }
Sample Dialogue
Enter account balance: $100.00 Enter account interest rate: 10.0 Enter the number of months until maturity (must be 12 or fewer months): 6 When your CD matures in 6 months, it will have a balance of $105.00
The structure definition is as follows:
struct CDAccount
{
double balance;
double interestRate;
int term; //months until maturity
};
The keyword struct
announces that this is a structure type definition. The identifier CDAccount
is the name of the structure type. The name of a structure type is called the structure tag. The tag can be any legal identifier (but not a keyword). Although this convention is not required by the C++ language, structure tags are usually spelled with a mix of uppercase and lowercase letters, beginning with an uppercase letter. The identifiers declared inside the braces, {}
, are called member names. As illustrated in this example, a structure type definition ends with both a brace, }
, and a semicolon.
A structure definition is usually placed outside of any function definition (in the same way that globally defined constant declarations are placed outside of all function definitions). The structure type is then available to all the code that follows the structure definition.
Once a structure type definition has been given, the structure type can be used just like the predefined types int
, char
, and so forth. For example, the following will declare two variables, named myAccount
and yourAccount
, both of type CDAccount
:
CDAccount myAccount, yourAccount;
A structure variable can hold values just like any other variable can hold values. A structure value is a collection of smaller values called member values. There is one member value for each member name declared in the structure definition. For example, a value of the type CDAccount
is a collection of three member values: two of type double
and one of type int
. The member values that together make up the structure value are stored in member variables, which we discuss next.
Each structure type specifies a list of member names. In Display 10.1 the structure CDAccount
has the three member names balance
, interestRate
, and term
. Each of these member names can be used to pick out one smaller variable that is a part of the larger structure variable. These smaller variables are called member variables. Member variables are specified by giving the name of the structure variable followed by a dot (that is, followed by a period) and then the member name. For example, if account
is a structure variable of type CDAccount
(as declared in Display 10.1), then the structure variable account
has the following three member variables:
account.balance
account.interestRate
account.term
The first two member variables are of type double
, and the last is of type int
. These member variables can be used just like any other variables of those types. For example, the member variables above can be given values with the following three assignment statements:
account.balance = 1000.00;
account.interestRate = 4.7;
account.term = 11;
The result of these three statements is diagrammed in Display 10.2. Member variables can be used in all the ways that ordinary variables can be used. For example, the following line from the program in Display 10.1 will add the value contained in the member variable account.balance
and the value contained in the ordinary variable interest
and will then place the result in the member variable account.balance
:
account.balance = account.balance + interest;
Notice that you specify a member variable for a structure variable by using the dot operator in the same way you used it in Chapter 6, where the dot operator was used to specify a member function of a class. The only difference is that in the case of structures, the members are variables rather than functions.
Two or more structure types may use the same member names. For example, it is perfectly legal to have the following two type definitions in the same program:
struct FertilizerStock
{
double quantity;
double nitrogenContent;
};
and
struct CropYield
{
int quantity;
double size;
};
This coincidence of names will produce no problems. For example, if you declare the following two structure variables:
FertilizerStock superGrow;
CropYield apples;
then the quantity of superGrow
fertilizer is stored in the member variable superGrow.quantity
and the quantity of apples produced is stored in the member variable apples.quantity
. The dot operator and the structure variable specify which quantity
is meant in each instance.
A structure value can be viewed as a collection of member values. Viewed this way, a structure value is many different values. A structure value can also be viewed as a single (complex) value (which just happens to be made up of member values). Since a structure value can be viewed as a single value, structure values and structure variables can be used in the same ways that you use simple values and simple variables of the predefined types such as int
. In particular, you can assign structure values using the equal sign. For example, if apples
and oranges
are structure variables of the type CropYield
defined earlier, then the following is perfectly legal:
apples = oranges;
This assignment statement is equivalent to:
apples.quantity = oranges.quantity;
apples.size = oranges.size;
When we assign a structure variable in this way we are performing a Shallow copy. This means that the individual member variables are directly copied. This works fine for simple variables, but we will see later that this can cause problems when variables are dynamically allocated.
A function can have call-by-value parameters of a structure type and/or call-by-reference parameters of a structure type. The program in Display 10.1, for example, includes a function named getData
that has a call-by-reference parameter with the structure type CDAccount
.
A structure type can also be the type for the value returned by a function. For example, the following defines a function that takes three appropriate arguments and returns a value of type CDAccount
:
CDAccount shrinkWrap(double theBalance,
double theRate, int theTerm)
{
CDAccount temp;
temp.balance = theBalance;
temp.interestRate = theRate;
temp.term = theTerm;
return temp;
}
Notice the local variable temp
of type CDAccount
; temp
is used to build up a complete structure value, which is then returned by the function. Once you have defined the function shrinkWrap
, you can give a value to a variable of type CDAccount
as illustrated by the following:
CDAccount newAccount;
newAccount = shrinkWrap(10000.00, 5.1, 11);
Sometimes it makes sense to have structures whose members are themselves smaller structures. For example, a structure type called PersonInfo
, which can be used to store a person’s height, weight, and birth date, can be defined as follows:
struct Date
{
int month;
int day;
int year;
};
struct PersonInfo
{
double height; //in inches
int weight; //in pounds
Date birthday;
};
A structure variable of type PersonInfo
is declared in the usual way:
PersonInfo person1;
If the structure variable person1
has had its value set to record a person’s birth date, then the year the person was born can be output to the screen as follows:
cout << person1.birthday.year;
The way to read such expressions is left to right, and very carefully. Starting at the left end, person1
is a structure variable of type PersonInfo
. To obtain the member variable with the name birthday
, use the dot operator as follows:
person1.birthday
This member variable is itself a structure variable of type Date
. Thus, this member variable has member variables itself. A member variable of the structure variable person1.birthday
is obtained by adding a dot and the member variable name, such as year
, which produces the expression person1. birthday.year
shown previously.
You can initialize a structure at the time that it is declared. To give a structure variable a value, you follow it by an equal sign and a list of the member values enclosed in braces. For example, the following definition of a structure type for a date was given in the previous subsection:
struct Date
{
int month;
int day;
int year;
};
Once the type Date
is defined, you can declare and initialize a structure variable called dueDate
as follows:
Date dueDate = {12, 31, 2004};
Be sure to notice that the initializing values must be given in the order that corresponds to the order of member variables in the structure type definition. In this example, dueDate.month
receives the first initializing value of 12
, dueDate.day
receives the second value of 31
, and dueDate.year
receives the third value of 2004
.
It is an error if there are more initializers than struct
members. If there are fewer initializer values than struct
members, the provided values are used to initialize data members, in order. Each data member without an initializer is initialized to a zero value of an appropriate type for the variable.
Given the following structure and structure variable declaration:
struct TermAccount
{
double balance;
double interestRate;
int term;
char initial1;
char initial2;
};
TermAccount account;
what is the type of each of the following? Mark any that are not correct.
account.balance
account.interestRate
TermAccount.term
savingsAccount.initial1
account.initial2
account
Consider the following type definition:
struct ShoeType
{
char style;
double price;
};
Given this structure type definition, what will be the output produced by the following code?
ShoeType shoe1, shoe2;
shoe1.style ='A';
shoe1.price = 9.99;
cout << shoe1.style << " $" << shoe1.price << endl;
shoe2 = shoe1;
shoe2.price = shoe2.price/9;
cout << shoe2.style << " $" << shoe2.price << endl;
What is the error in the following structure definition? What is the message your compiler gives for this error? State what the error is, in your own words.
struct Stuff
{
int b;
int c;
}
int main( )
{
Stuff x;
//other code
}
Given the following struct
definition:
struct A
{
int memberB;
int memberC;
};
declare x to have this structure type. Initialize the members of x, memberB
and memberC
, to the values 1
and 2
, respectively.
(Note: This requests an initialization, not an assignment of the members. This distinction is important and will be made in a later chapter.)
Here is an initialization of a structure type. Tell what happens with each initialization. Note any problems with these initializations.
struct Date
{
int month;
int day;
int year;
};
Date dueDate = {12, 21};
Date dueDate = {12, 21, 20, 22};
Date dueDate = {12, 21, 20, 22};
Date dueDate = {12, 21, 22};
Write a definition for a structure type for records consisting of a person’s wage rate, accrued vacation (which is some whole number of days), and status (which is either hourly or salaried). Represent the status as one of the two char
values 'H'
and 'S'
. Call the type EmployeeRecord
.
Give a function definition corresponding to the following function declaration. (The type ShoeType
is given in Self-Test Exercise 2.)
void readShoeRecord(ShoeType& newShoe);
//Fills newShoe with values read from the keyboard.
Give a function definition corresponding to the following function declaration. (The type ShoeType
is given in Self-Test Exercise 2.)
ShoeType discount(ShoeType oldRecord);
//Returns a structure that is the same as its argument,
//but with the price reduced by 10%.
Give the structure definition for a type named StockRecord
that has two member variables, one named shoeInfo
of the type ShoeType
given in Self-Test Exercise 2 and one named arrivalDate
of type Date
given in Self-Test Exercise 5.
Declare a variable of type StockRecord
(given in the previous exercise) and write a statement that will set the year of the arrival date to 2006
.