Tải bản đầy đủ (.pdf) (10 trang)

Absolute C++ (4th Edition) part 30 pdf

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (313.91 KB, 10 trang )

Vectors—A Preview of the Standard Template Library 293
Pitfall
The vector definition is given in the library vector, which places it in the std
namespace. Thus, a file that uses vectors would include the following (or something
similar):
#include <vector>
using namespace std;
U
SING
S
QUARE
B
RACKETS

BEYOND

THE
V
ECTOR
S
IZE
If v is a vector and i is greater than or equal to v.size( ), then the element v[i] does not yet
exits and needs to be created by using
push_back to add elements up to and including position
i. If you try to set v[i] for i greater than or equal to v.size( ), as in
v[i] = n;
then you may or may not get an error message, but your program will undoubtedly misbehave at
some point.
V
ECTORS
Vectors are used very much like arrays, but a vector does not have a fixed size. If it needs more


capacity to store another element, its capacity is automatically increased. Vectors are defined in
the library
vector, which places them in the std namespace. Thus, a file that uses vectors would
include the following lines:
#include <vector>
using namespace std;
The vector class for a given
Base_Type
is written vector<
Base_Type
>. Two sample vector decla-
rations are as follows:
vector<int> v; //default constructor producing an empty vector.
vector<AClass> record(20); //vector constructor uses the
//default constructor for AClass to initialize 20 elements.
Elements are added to a vector using the member function push_back, as illustrated below:
v.push_back(42);
Once an element position has received its first element, either with push_back or with a con-
structor initialization, that element position can then be accessed using square bracket notation,
just like an array element.
07_CH07.fm Page 293 Wednesday, August 13, 2003 12:58 PM
294 Constructors and Other Tools
Tip
V
ECTOR
A
SSIGNMENT
I
S
W

ELL
B
EHAVED
The assignment operator with vectors does an element-by-element assignment to the vector on
the left-hand side of the assignment operator (increasing capacity if needed and resetting the
size of the vector on the left-hand side of the assignment operator). Thus, provided the assign-
ment operator on the base type makes an independent copy of an element of the base type, then
the assignment operator on the vector will make an independent copy, not an alias, of the vector
on the right-hand side of the assignment operator.
Note that for the assignment operator to produce a totally independent copy of the vector on the
right-hand side of the assignment operator requires that the assignment operator on the base
type make completely independent copies. The assignment operator on a vector is only as good
(or bad) as the assignment operator on its base type.

EFFICIENCY ISSUES
At any point in time a vector has a capacity, which is the number of elements for which
it currently has memory allocated. The member function
capacity( ) can be used to
find out the capacity of a vector. Do not confuse the capacity of a vector with the size of
a vector. The size is the number of elements in a vector, whereas the capacity is the
number of elements for which there is memory allocated. Typically the capacity is
larger than the size, and the capacity is always greater than or equal to the size.
Whenever a vector runs out of capacity and needs room for an additional member,
the capacity is automatically increased. The exact amount of the increase is implemen-
tation dependent, but always allows for more capacity than is immediately needed. A
commonly used implementation scheme is for the capacity to double whenever it needs
to increase. Because increasing capacity is a complex task, this approach of reallocating
capacity in large chunks is more efficient than allocating numerous small chunks.
You can completely ignore the capacity of a vector and that will have no effect on
what your program does. However, if efficiency is an issue, you may want to manage

capacity yourself and not simply accept the default behavior of doubling capacity
whenever more is needed. You can use the member function
reserve to explicitly
increase the capacity of a vector. For example,
v.reserve(32);
sets the capacity to at least 32 elements, and
v.reserve(v.size( ) + 10);
sets the capacity to at least 10 more than the number of elements currently in the vec-
tor. Note that you can rely on
v.reserve to increase the capacity of a vector, but it does
not necessarily decrease the capacity of a vector if the argument is smaller than the cur-
rent capacity.
capacity
07_CH07.fm Page 294 Wednesday, August 13, 2003 12:58 PM
Vectors—A Preview of the Standard Template Library 295
Self-Test Exercises
You can change the size of a vector using the member function resize. For example,
the following resizes a vector to 24 elements:
v.resize(24);
If the previous size were less than 24, then the new elements are initialized as we
described for the constructor with an integer argument. If the previous size were greater
than 24, then all but the first 24 elements are lost. The capacity is automatically
increased if need be. Using
resize and reserve, you can shrink the size and capacity of
a vector when there is no longer any need for some elements or some capacity.
9. Is the following program legal? If so, what is the output?
#include <iostream>
#include <vector>
using namespace std;
int main( )

{
vector<int> v(10);
int i;

for (i = 0; i < v.size( ); i++)
v[i] = i;
vector<int> copy;
copy = v;
v[0] = 42;
for (i = 0; i < copy.size( ); i++)
cout << copy[i] << " ";
cout << endl;
return 0;
}
10. What is the difference between the size and the capacity of a vector?
S
IZE

AND
C
APACITY
The size of a vector is the number of elements in the vector. The capacity of a vector is the number
of elements for which it currently has memory allocated. For a vector
v, the size and capacity can
be recovered with the member functions
v.size( ) and v.capacity( ).
07_CH07.fm Page 295 Wednesday, August 13, 2003 12:58 PM
296 Constructors and Other Tools
■ A constructor is a member function of a class that is called automatically when an
object of the class is declared. A constructor must have the same name as the class of

which it is a member.
■ A default constructor is a constructor with no parameters. You should always
define a default constructor for your classes.
■ A member variable for a class may itself be of a class type. If a class has a class mem-
ber variable, then the member variable constructor can be invoked in the initializa-
tion section of the outer class constructor.
■ A constant call-by-reference parameter is more efficient than a call-by-value parame-
ter for class type parameters.
■ Making very short function definitions inline can improve the efficiency of your
code.
■ Static member variables are variables that are shared by all objects of a class.
■ Vector classes have objects that behave very much like arrays whose capacity to hold
elements will automatically increase if more capacity is needed.
ANSWERS TO SELF-TEST EXERCISES
1. YourClass anObject(42, ’A’); //LEGAL
YourClass anotherObject; //LEGAL
YourClass yetAnotherObject(
); //PROBLEM
anObject = YourClass(99, ’B’); //LEGAL
anObject = YourClass(
); //LEGAL
anObject = YourClass; //ILLEGAL
The statement marked //PROBLEM is not strictly illegal, but it does not mean what you
might think it means. If you mean this to be a declaration of an object called
yetAnotherObject, then it is wrong. It is a correct declaration for a function called
yetAnotherObject that takes zero arguments and that returns a value of type YourClass,
but that is not usually the intended meaning. As a practical matter, you can probably
consider it illegal. The correct way to declare an object called
yetAnotherObject so that it
will be initialized with the default constructor is as follows:

YourClass yetAnotherObject;
2. A default constructor is a constructor that takes no arguments. Not every class has a default
constructor. If you define absolutely no constructors for a class, then a default constructor
will be automatically provided. On the other hand, if you define one or more constructors
but do not define a default constructor, then your class will have no default constructor.
Chapter Summary
07_CH07.fm Page 296 Wednesday, August 13, 2003 12:58 PM
Answers to Self-Test Exercises 297
3. The definition is easier to give if you also add a private helping function named BankAc-
count::digitToInt
, as below, to the class BankAccount.
//Uses iostream:
void BankAccount::input( )
{
int dollars;
char point, digit1, digit2;
cout <<
"Enter account balance (include cents even if .00) $";
cin >> dollars;
cin >> point >> digit1 >> digit2;
accountDollars = dollars;
accountCents = digitToInt(digit1)*10 + digitToInt(digit2);
if (accountDollars < 0)
accountCents = -accountCents;
cout << "Enter interest rate (NO percent sign): ";
cin >> rate;
setRate(rate);
}
int BankAccount::digitToInt(char digit)
{

return (static_cast<int>(digit) - static_cast<int>(’0’));
}
4. The member function input changes the value of its calling object, and so the compiler
will issue an error message if you add the
const modifier.
5. Similarities: Each parameter call method protects the caller’s argument from change. Dif-
ferences: If the type is a large structure or class object, a call by value makes a copy of the
caller’s argument and thus uses more memory than a call by constant reference.
6. In
const int x = 17;, the const keyword promises the compiler that code written by
the author will not change the value of
x.
In the
int f( ) const; declaration, the const keyword is a promise to the compiler that
code written by the author to implement function
f will not change anything in the calling
object.
In
int g(const A& x);, the const keyword is a promise to the compiler that code
written by the class author will not change the argument plugged in for
x.
7.
class DayOfYear
{
public:
DayOfYear(int monthValue, int dayValue);
DayOfYear(int monthValue);
DayOfYear( );
07_CH07.fm Page 297 Wednesday, August 13, 2003 12:58 PM
298 Constructors and Other Tools

void input( );
void output( );
int getMonthNumber( ) { return month; }
int getDay( ) { return day; }
private:
int month;
int day;
void testDate( );
};
8. No, it cannot be a static member function because it requires a calling object for the mem-
ber variable
name.
9. The program is legal. The output is
0 1 2 3 4 5 6 7 8 9
Note that changing v does not change copy. A true independent copy is made with the
assignment.
copy = v;
10. The size is the number of elements in a vector, while the capacity is number of elements for
which there is memory allocated. Typically the capacity is larger than the size.
PROGRAMMING PROJECTS
1. Define a class called Month that is an abstract data type for a month. Your class will have
one member variable of type
int to represent a month (1 for January, 2 for February, and
so forth). Include all the following member functions: a constructor to set the month using
the first three letters in the name of the month as three arguments, a constructor to set the
month using an integer as an argument (1 for January, 2 for February, and so forth), a
default constructor, an input function that reads the month as an integer, an input func-
tion that reads the month as the first three letters in the name of the month, an output
function that outputs the month as an integer, an output function that outputs the month
as the first three letters in the name of the month, and a member function that returns the

next month as a value of type
Month. Embed your class definition in a test program.
2. Redefine the implementation of the class
Month described in Programming Project 1. (or
do the definition for the first time, but do the implementation as described here). This time
the month is implemented as three member variables of type
char that store the first three
letters in the name of the month. Embed your definition in a test program.
3. My mother always took a little red counter to the grocery store. The counter was used to
keep tally of the amount of money she would have spent so far on that visit to the store if
she bought everything in the basket. The counter had a four-digit display, increment but-
tons for each digit, and a reset button. An overflow indicator came up red if more money
was entered than the
$99.99 it would register. (This was a long time ago.)
07_CH07.fm Page 298 Wednesday, August 13, 2003 12:58 PM
1
.
7
2
.
6
Programming Projects 299
Write and implement the member functions of a class Counter that simulates and slightly
generalizes the behavior of this grocery store counter. The constructor should create a
Counter object that can count up to the constructor’s argument. That is, Counter(9999)
should provide a counter that can count up to
9999. A newly constructed counter displays
a reading of
0. The member function void reset( ); sets the counter’s number to 0. The
member function

void incr1( ); increments the units digits by 1, void incr10( );
increments the tens digit by
1, and void incr100( ); and void incr1000( ); increment
the next two digits, respectively. Accounting for any carrying when you increment should
require no further action than adding an appropriate number to the private data member.
A member function
bool overflow( ); detects overflow. (Overflow is the result of
incrementing the counter’s private data member beyond the maximum entered at counter
construction.)
Use this class to provide a simulation of my mother’s little red clicker. Even though the
display is an integer, in the simulation, the rightmost (lower order) two digits are always
thought of as cents and tens of cents, the next digit is dollars, and the fourth digit is tens of
dollars.
Provide keys for cents, dimes, dollars, and tens of dollars. Unfortunately, no choice of keys
seems particularly mnemonic. One choice is to use the keys
asdfo: a for cents, followed by
a digit
1 to 9; s for dimes, followed by a digit 1 to 9; d for dollars, followed by a digit 1 to
9; and f for tens of dollars, again followed by a digit 1 to 9. Each entry (one of asdf
followed by
1 to 9) is followed by pressing the Return key. Any overflow is reported after
each operation. Overflow can be requested by pressing the
o key.
07_CH07.fm Page 299 Wednesday, August 13, 2003 12:58 PM
7.4
For additional online
Programming Projects,
click the CodeMate icons
below.


8

Operator Overloading, Friends,
and References
8.1 BASIC OPERATOR OVERLOADING 302
Overloading Basics 303
Tip: A Constructor Can Return an Object 308
Returning by

const
Value 309
Tip: Returning Member Variables of a Class Type 312
Overloading Unary Operators 313
Overloading as Member Functions 314
Tip: A Class Has Access to All Its Objects 316
Overloading Function Application

( )
317
Pitfall: Overloading

&&
,

||
, and the Comma Operator 317
8.2 FRIEND FUNCTIONS AND AUTOMATIC
TYPE CONVERSION 318
Constructors for Automatic Type Conversion 318
Pitfall: Member Operators and Automatic Type Conversion 319

Friend Functions 320
Pitfall: Compilers without Friends 323
Friend Classes 323
8.3 REFERENCES AND MORE OVERLOADED OPERATORS 324
References 325
Pitfall: Returning a Reference to Certain Member Variables 327
Overloading

>>
and

<<
327
Tip: What Mode of Returned Value to Use 335
The Assignment Operator 336
Overloading the Increment and Decrement Operators 337
Overloading the Array Operator [

] 337
Overloading Based on L-Value versus R-Value 341
CHAPTER SUMMARY 342
ANSWERS TO SELF-TEST EXERCISES 342
PROGRAMMING PROJECTS 345

08_CH08.fm Page 301 Wednesday, August 13, 2003 1:02 PM

8

Operator Overloading, Friends,
and References


Eternal truths will be neither true nor eternal unless they have fresh
meaning for every new social situation.



Franklin D. Roosevelt, Address at the University of Pennsylvania
[September 20, 1940]
INTRODUCTION

This chapter discusses a number of tools to use when defining classes. The first
tool is operator overloading, which allows you to overload operators, such as

+

and

==

,



so that they apply to objects of the classes you define. The second tool
is the use of friend functions which are functions that are not members of a
class but still have access to the private members of the class. This chapter also
discusses how to provide automatic type conversion from other data types to
the classes you define.
If you have not yet covered arrays (Chapter 5), you should skip the subsec-
tion of 8.3 entitled


Overloading the Array Operator [ ]

. It covers a topic that
may not make sense unless you know about array basics.

Basic Operator Overloading

He’s a smooth operator.

Line from a song by Sade (written by Sade Adu and Ray St. John)

Operators such as

+

,

-

,

%

,

==

, and so forth are nothing but functions that are
used with a slightly different syntax. We write


x + 7

rather than

+(x, 7)

, but
the

+

operator is a function that takes two arguments (often called

operands

rather than arguments) and returns a single value. As such, operators are not
really necessary. We could make do with

+(x, 7)

or even

add(x, 7)

. Oper-
ands are an example of what is often called

syntactic sugar


, meaning a slightly
different syntax that people like. However, people are very comfortable with
the usual operator syntax,

x + 7

, that C++ uses for types such as

int

and

dou-
ble

. And one way to view a high-level language, such as C++, is as a way to
make people comfortable with programming computers. Thus, this syntactic
sugar is probably a good idea; at the least, it is a well-entrenched idea. In C++
you can overload the operators, such as

+

and

==

, so that they work with oper-
ands in the classes you define. The way to overload an operator is very similar
to the way you overload a function name. The details are best explained
through an example.

8.1
operators and
functions
operand
syntactic
sugar

08_CH08.fm Page 302 Wednesday, August 13, 2003 1:02 PM
Basic Operator Overloading 303


OVERLOADING BASICS

Display 8.1 contains the definition of a class whose values are amounts of U.S. money,
such as $9.99 or $1567.29. The class has a lot in common with the

BankAccount

class
we defined in Display 7.2. It represents amounts of money in the same way, as two

int

s
for the dollars and cents parts. It has the same private helping functions. Its construc-
tors and accessor and mutator functions are similar to those of the class

BankAccount

.

What is truly new about this

Money

class is that we have overloaded the plus sign and
the minus sign so they can be used to add or subtract two objects of the class

Money

,
and we have overloaded the

==

sign so it can be used to compare two objects of the class

Money

to see if they represent the same amount of money. Let’s look at these overloaded
operators.
You can overload the operator

+

(and many other operators) so that it will accept
arguments of a class type. The difference between overloading the

+

operator and defin-

ing an ordinary function involves only a slight change in syntax: You use the symbol

+

as the function name and precede the

+

with the keyword

operator

. The operator dec-
laration (function declaration) for the plus sign is as follows:

const Money operator +(const Money& amount1, const Money& amount2);

The operands (arguments) are both constant reference parameters of type

Money

. The
operands can be of any type, as long as at least one is a class type. In the general case,
operands may be call-by-value or call-by-reference parameters and may have the

const

modifier or not. However, for efficiency reasons, constant call by reference is usually
used in place of call by value for classes. In this case the value returned is of type


Money

,
but in the general case the value returned can be of any type, including

void

. The

const

before the returned type

Money

will be explained later in this chapter. For now,
you can safely ignore that

const

.
Note that the overloaded binary operators

+

and

-

are not member operators (mem-

ber functions) of the class

Money

and therefore do not have access to the private mem-
bers of the class

Money

. That is why the definition for the overloaded operators uses
accessor and mutator functions. Later in this chapter we will see other ways of over-
loading an operand, including overloading it as a member operator. Each of the differ-
ent ways of overloading an operator has its advantages and disadvantages.
The definitions of the overloaded binary operators

+

and

-

are perhaps a bit more
complicated than you might expect. The extra details are there to cope with the fact
that amounts of money can be negative.
The unary minus sign operator

-

is discussed in the subsection


Overloading Unary
Operators

, later in this chapter.
The operator

==

is also overloaded so that it can be used to compare two objects of
the class

Money

. Note that the type returned is

bool

so that

== can be used to make
comparisons in the usual ways, such as in an
if-else statement.
how to
overload
an operator
08_CH08.fm Page 303 Wednesday, August 13, 2003 1:02 PM

×