Previous section   Next section

Imperfect C++ Practical Solutions for Real-Life Programming
By Matthew Wilson
Table of Contents
Chapter 4.  Data Encapsulation and Value Types


4.7. Arithmetic Value Types

The last step on the ladder is to move on and provide support for other operators, so that our types can participate in natural expressions, such as:



uinteger64  i1 = . . .;


uinteger64  i2 = . . .;


bool        bLess   = i1 < i2;  // Ok


bool        bEqual  = i1 == i2; // Ok


uinteger64  i3      = i1 + i2;  // Ok





i3 %= i1;


i1 = i2 *= i3;



The first operator we're going to be concerned with is the less-than operator (operator <()), since it is this that will allow types to be ordered. A type that can enter into a less-than comparison is called LessThanComparable [Aust1999]; this is an essential characteristic of types that are supported by the STL. Indeed, in the standard, this is the only ordering operator required. I must admit that I've a tendency to stick to using this one exclusively, even when it causes me to write less clear code such as assert(!(size() < index)), rather than assert(index <= size()); I'm not sure that's to be advised.

Given the definition of UInteger64, we can follow the example of the (in)equality operators, and supply this as a nonmember function. Now we can add UInteger64 instances into a std::set or a std::map, if we choose.

There are many other arithmetic operators that can potentially be provided. Whether we do so depends on the type. For our UInteger64 type it is likely that we'd want to provide all of them, +, -, *, /, %, ~, <<, >>, &, |, ^ and all the corresponding assignment operators, because our type is an integer. (We'll look at the best ways to implement such things in Chapter 29.) We see a great example of the provision of free operators in the true_typedef template class (section 18.4), where all the arithmetic operators are provided for the class as free functions, and we can do the same for other types.

The important thing is to define only those operators as are appropriate. If we had a currency type we would certainly want to be able to add and subtract two Currency instances using the + and – operators, but not be able to multiply them: What is $6.50 x £2.93? Conversely, we'd want to be able to multiply a numeric value and a Currency instance together, but not be able to add or subtract them.

Of course, C++ allows you to define any operators for any class types and have them do anything. This is open to considerable abuse (see Appendix B). Indeed, we saw at the start of the chapter that the String class had defined the + and ++ operators. Use of + to concatenate strings is wrong[6] since it does not perform an arithmetic sum on its operands. However, this is of such utility that we all, almost to a man, gloss over the immorality and revel in the convenience. (Convenient it may be, but it's not efficient. We'll see how to make it a lot more efficient in Chapter 25.)

[6] This is another of those "contentious" statements that are going to buy me a lot of flak. Just remember that just because something is widely accepted, and even useful, does not necessarily make it right. There're plenty of examples of that in this book.

Despite operator abuse being sanctioned at the highest levels, it is sick and you should not be tempted to do it. I know: I've been bad. Very bad (see Appendix B).


      Previous section   Next section