Browse DevX
Sign up for e-mail newsletters from DevX


Preserve Code Safety with Conversion Operators-2 : Page 2

Demonstrating the Problem
Commercial and financial applications often represent monetary values as objects rather than native floating-point types. There are several good reasons for this approach:
  • Type-safety: Human errors are detected more easily this way.
  • Portability: As implementation details are hidden from users, your code becomes more portable.
  • Business logic: A class allows you to enforce business logic rules. For example, a US dollar class knows that a dollar has 100 cents whereas a Kuwaiti dinar class knows that a dinar has 1000 fils. This knowledge affects I/O formatting, for example.
Here's a simplified class representing US currency:

class USD
 __int64 dollars; //or long long, depending on compiler 
 int cents;
 USD(__int64 d=0, int c=0) : 
  dollars(d), cents(c) {}
friend bool operator==(const USD& d1, const USD& d2);
 //...other overloaded operators and functions
Alas, many math functions such as pow() and sqrt() will accept only floating-point variables. To overcome this problem it might seem tempting to overload relational and arithmetic operators. However, you'll soon discover that this incurs excessive code writing, testing and maintenance for no real purpose. What you really want is a dual interface: class USD should provide the advantages of a real object listed above while offering a safe and automatic conversion to fundamental types in the appropriate contexts.

Using Conversion Operators
A conversion operator converts its object to a different type automatically in an appropriate context. In class USD, the most natural conversion is to double:

USD payment(203, 67);
In this case, you want a conversion of the payment object to the floating point value 203.67.

A conversion operator has no return value (it's deduced from the operator's name) and it takes no arguments either:

class USD
 operator double() //conversion operator
  double temp=(dollars*100)+cents;
  return temp/100;
Let's see how it works. Suppose you want to increase payment by 5 percent:

double res=payment*1.05; //res=210.70
This works fine because the conversion operator automatically converts payment to the value 200.67 before the multiplication. However, there is a serious flaw in the design of class USD. Consider the following statement:

payment=payment*1.05; //bad
Now, payment equals 210.00, which is certainly not the expected result. Let's see why. The right-hand sub-expression payment*1.05 is evaluated first. As you've just seen, this part is kosher and produces the correct result. The problem is with the assignment. The compiler evaluates the assignment expression as follows:

payment=USD(__int64(200.67*1.05), 0);
The result of the multiplication expression is implicitly converted to an integral type (thus losing the fraction part) and is then used as an argument of a temporary USD object. That's why it yielded such an embarrassing result.

Thanks for your registration, follow us on our social networks to keep up-to-date