Read an Excerpt
From Chapter Ten: Working with Classes
You will learn about the following in this chapter:
- Operator overloading
- Firend functions
- Overloading the << operator for output
- State members
Using rand() to generate random values
- Automatic conversions and type casts for classes
- Class conversion functions
This chapter starts with operator overloading, which lets you use standard C++ operators such as = and + with class objects. Then it examines friends, the C++ mechanism for letting nonmember functions access private data. Finally it looks at how you can instruct C++ to perform automatic type conversions with classes. As you go through this and the next chapter, you'll gain a greater appreciation of the roles class constructors and class destructors play. Also, you'll see some of the stages you may go through as you develop and improve a class design.
One difficulty with learning C++, at least by the time you've gotten this far into the subject, is that there is an awful lot to remember. And its unreasonable to expect to remember, it all until you've logged enough experience on which to hang your memories. Learning C++, in this respect, is like learning a feature-laden word processor or spreadsheet program. No one feature is that daunting, but, in practice, most people really know well only those features they use regularly, such as searching for text or italicizing. You may recall having read somewhere how to generate alternative characters or create a table of contents, but those skills probably won't be part of your daily repertoire until you find yourself in a situation in which you need them frequently probably the best approach to absorbing the wealth of material in this chapter is to begin incorporating just some of these new features into your own C++ programming. As your experiences enhance your understanding and appreciation of these features, begin adding other C++ features. As Bjarne Stroustrup, the creator of C++, suggested at a C++ conference for professional programmers: "Ease yourself into the language. Don't feel you have to use all of the features, and don't try to use them all on the first day."
Let's look at a technique for giving object operations a prettier look. Operator overloading is another example of C++ polymorphism. In Chapter 8, you saw how C++ enables you to define several functions having the same name as long as they have different signatures (argument lists). That was function overloading, or functional polymorphism. Its purpose is to let you use the same function name for the same basic operation even though you apply the operation to different data types. (imagine how awkward English would be if you had to use a different verb form for each different type of object--lift_lft your left foot, but lift_sp your spoon.) Operator overloading extends the overloading concept to operators, letting you assign multiple meanings to C++ operators. Actually many C++ (and C) operators already are overloaded. For example, the * operator, when applied to an address, yields the value stored at that address. But applying * to two numbers yields the product of the values. C++ uses the number and type of operands to decide which action to take.
C++ lets you extend operator overloading to user-defined types, permitting you, say, to use the + symbol to add two objects. Again, the compiler will use the number and type of operands to determine which definition of addition to use. Overloaded operators often can make code look more natural. For example, a common computing task is adding two arrays, Usually, this winds up looking like the following for loop:
for (int i = 0; i < 20; i++)
evening[i] = sam[i] + janet [I];// add element by element
But in C++, you can define a class that represents arrays and that overloads the + operator so that you can do this:
evening = sam + janet; // add two array objects
We'll do just that in Chapter 12. (Why not now? Because you also have to overload the [ ] operator, and that's a bit more involved than overloading the + operator.) This simple addition notation conceals the mechanics and emphasizes what is essential, and that is another 00P goal.
To overload in operator, you use a special function form called an operator function. An operator function has the form:
where op is the symbol for the operator being overloaded. That is, operator+ overloads the + operator (op is +) and operator* ( ) overloads the * operator (op is *). The op has to be a valid C++ operator ' you can't just make up a new symbol. For example, you can't have in operator@( ) function because C++ has no @ operator. But the operator [ ] ( ) function would overload the [ ] operator because [ ] is the array-indexing operator. Suppose, for example, that you have a Salesperson class for which you define an operator+ ( ) member function to overload the + operator so that it adds sales figures of one salesperson object to another. Then, if district2, sid, and sara all are objects of the salesperson class, you can write this equation:
district2 = sid + sara;
The compiler, recognizing the operands as belonging to the Salesperson class, will replace the operator with the corresponding operator function:
district2 = sid.operator+(sara);
The function will then use the sid object implicitly (because it invoked the method) and the sara object explicitly (because it's passed as an argument) to calculate the sum, which it then returns. Of course, the nice part is that you can use the nifty + operator notation instead of the clunky function notation.
C++ imposes some restrictions on operator overloading, but they're easier to understand alter you've seen how overloading works. So let's develop a few examples first to clarify the process and then discuss the limitations.
Time on Our Hands
If you worked on the Priggs account 2 hours 35 minutes in the morning and 2 hours 40 Minutes in the afternoon, how long did you work altogether on the account? Here's an example where the concept of addition makes sense, but the units that you are adding (a mixture of hours and minutes ) doesn't match a built-in type. Chapter 7 handled a similar case by defining a travel_time structure and a sum( ) function for adding such structures. Now we can generalize that to a Time class using a method to handle addition, Let's begin with an ordinary method, then see how to convert it to an overloaded operator. Listing 10.1 shows the class declaration...