- 2.1. Our emphasis
- 2.2. The basic goal—a major difference between C++ and Java
- 2.3. Constructors and destructor
- 2.4. Operator overloading in C++
- 2.5. Operator overloading in Java
- 2.6. Flow-control constructs
- 2.7. Manipulating character strings in C++
- 2.8. Canonical class structure
- 2.9. Overcoming macrophobia
- 2.10. Program readability
- 2.11. Error detection and exceptions
2.2. The basic goal—a major difference between C++ and Java
C++ encourages us to minimize the differences between built-in or primitive data and instances of user-defined classes. Bjarne Stroustrup, the principal designer of C++, advises language designers: “Provide as good support for user-defined types as for built in types.”1 Numeric data type classes are especially suited to such consistency because of the natural way in which programs manipulate them using C’s rich set of operators.
Consider this program fragment, valid in C, C++, and Java:
double creditLimit; double unitPrice= 49.95; double totalPrice = 0; int quantityOrdered; . . totalPrice += quantityOrdered * unitPrice; if (totalPrice > creditLimit) . .
Now suppose we later discover or develop a Money class that supports everything a program might do to amounts of money and also alleviates auditors’ anxiety about floating-point rounding error. What would we have to change in the above example to exploit the Money class?
In C++, we’d change only the type name in the three declarations:
Money creditLimit; Money unitPrice= 49.95; Money totalPrice = 0;
If the Money class supports the basic goal, then the executable statements will require no change at all. We wouldn’t even have needed to change the three declarations if we’d had the foresight, as experienced C programmers do routinely, to localize the original choice of primitive type:
typedef double Money;
A basic goal in C++, for both the language itself and for anyone designing a class, is the following:
- Objects, especially elementary data types, should behave as much as possible like built-in primitive data.
In Java, it’s just the opposite!
Java is actually two distinct expression languages in one package: one for manipulating primitive built-in data items, and one for manipulating objects or reference data items. They are different in almost every way.
To change the program fragment to exploit a Java Money class, we’ll need to change every statement that refers to a Money data item. The result might look like this:
Money creditLimit; Money unitPrice= new Money(49.95); Money totalPrice = new Money(0); int quantityOrdered; . . totalPrice.addSet(unitPrice.mpy(quantityOrdered)); if (totalPrice.greaterThan(creditLimit)) .
In Java, then, elementary objects behave differently from built-in primitive types, in almost every context.
Although it’s tempting to complain about this or even to argue against using Java for computation, we shall not do so in this book. Java’s designers believed they had valid reasons for rejecting the C++ basic goal, and organizations often have valid reasons for choosing to develop applications in Java. We shall focus on making the best use of the facilities that Java does support, and we’ll leave the language arguments to other forums.
In either C++ or Java, you have to go to a lot of trouble to design and develop a robust and complete class for Money or any other numeric data type. It’s marginally worth doing so for a single program or a single project. What justifies the effort is the huge multiplier that results from using those class definitions in every program developed in your organization or even in multiple organizations. Once such a class is developed, packaged, and distributed, that problem is solved forever.
Problems and exercises
2.2-1 Many Java programmers and some C++ programmers forgo defining classes for numeric data. Instead, they just use double, int, or another built-in primitive type. The executable statements are then similar to those in FORTRAN, C, or another procedural language. Discuss the pros and cons of that approach. Consider ease of coding, ease of debugging, ease of change, readability, reliability, and efficiency.
2.2-2 Other programmers go to the opposite extreme, defining “wrapper” classes so that the numeric objects are bona fide objects. Then, instead of supporting operators and other functions that would operate on the object, the programmers provide accessor and modifier functions to retrieve and store the internal representation, performing their operations on the built-in primitive value. The executable part of the Money example might look like this in either C++ or Java:
totalPrice.setValue(totalPrice.getValue() + quantityOrdered * unitPrice.getValue()); if(totalPrice.getValue() > creditLimit.getValue()) . .
Discuss the pros and cons of that approach.