Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

DECIMAL Wrapper Class

0.00/5 (No votes)
18 May 2003 1  
A simple DECIMAL wrapper class suitable for C++ code interfacing VB scripts/OLE automation code etc.

Sample Image - decimalwrap.png

Introduction

This is a simple utility class which encapsulates the OLE Automation type DECIMAL. It's intended purpose is to rid the user of ::VarDecXXX() calls and make the DECIMALs "behave just like ints".

Interoperability

My class, Decimal, inherits publically from DECIMAL. The benefit of this is that anywhere you can put a DECIMAL, you can also put a Decimal. This makes the class fully interoperable with raw COM interfaces.

Unlike ATL, I do not overload the address of operator (operator&), so there is no need to adapt this class with CAdapt<> in order to contain it in STL containers.

Interface

All methods and constructors share the property throw() - i.e., no method will ever throw an exception. However, in debug builds, asserts may be triggered. Division by zero comes to mind. But you already know you shouldn't be dividing with zero, right?

All methods which return a Decimal& value, returns a reference to *this. Hence it is possible to stack such methods/operations.

Constructors

There are ten constructors. They are:

  • Decimal()

    Initializes the object with value 0.

  • Decimal(const DECIMAL& decValue)

    Initializes the object with the value which is contained in parameter decValue.

  • Decimal(char nValue)
  • Decimal(short nValue)
  • Decimal(long nValue)
  • Decimal(unsigned char nValue)
  • Decimal(unsigned short nValue)
  • Decimal(unsigned long nValue)

    Initializes the object with the integer value contained in parameter nValue.

  • Decimal(float fValue)
  • Decimal(double fValue)

    Initializes the object with the real value contained in parameter nValue.

Mutating operators

The following operators are defined, and behaves just like ints (hence I will not explain their usage and function!):

  • Decimal& operator = (char nValue)
  • Decimal& operator = (short nValue)
  • Decimal& operator = (long nValue)
  • Decimal& operator = (unsigned char nValue)
  • Decimal& operator = (unsigned short nValue)
  • Decimal& operator = (unsigned long nValue)
  • Decimal& operator = (float fValue)
  • Decimal& operator = (double dValue)
  • Decimal& operator += (const DECIMAL& decRHS)
  • Decimal& operator -= (const DECIMAL& decRHS)
  • Decimal& operator *= (const DECIMAL& decRHS)
  • Decimal& operator /= (const DECIMAL& decRHS)
  • Decimal operator++(int)
  • Decimal operator--(int)
  • Decimal& operator++()
  • Decimal& operator--()

Each operator operates just as if they had been defined for ints.

Mutating methods

  • bool FromString(LPCOLESTR lpszNum, LCID lcid = 0)

    Parses a string pointed to by lpszNum using the locale identifier lcid. The parsed value is then assigned to this object before returning.

    Should this function fail because of a badly formatted string, the return value is false.

    If the locale identifier, lcid, is 0, then the default system locale will be used to parse the string.

  • Decimal& MakeAbsolute()

    Makes this value an absolute value.

  • Decimal& MakeNegative()

    Makes this value a negative value.

  • Decimal& MakeInteger()

    Makes this value an integer by removing its fractional part. The semantics of this function is as follows: If the value is negative, then the first negative integer less than or equal to this value is returned. (Semantic description was copied and adapted from the MSDN documentation. Please see manual page for VarDecInt for the original text.)

  • Decimal& MakeFixed()

    Makes this value an integer by removing its fractional part. The semantics of this function is as follows: If the value is negative, then the first negative integer greater than or equal to this value is returned. (Semantic description was copied and adapted from the MSDN documentation. Please see manual page for VarDecFix for the original text.)

  • Decimal& MakeRound(int n)

    Rounds this value up to the nth decimal.

    Note that n must be greater or equal to zero.

Non-Mutating methods

The following functions are non-mutating. They are related to their mutating cousins described above, therefore I will just mention them here. For example, if a method mentioned below is named Absolute, then please see the documentation above for MakeAbsolute. These methods all share the common property that they do not modify the current value. Instead they create a temporary value which is modified and returned.

  • Decimal Absolute() const
  • Decimal Negative() const
  • Decimal Integer() const
  • Decimal Fixed() const
  • Decimal Round() const

Inspectors

  • bool IsNegative() const

    Predicate which returns true if this value is negative.

  • bool IsZero() const

    Predicate which returns true if this value is negative. This is the fastest way to test whether a Decimal is zero or not.

  • BSTR ToString(LCID lcid = 0) const

    Converts this value into a BSTR string using the specified locale. If the locale identifier, lcid, is zero, then the systems default locale will be used.

Free functions

The following free functions, although logically members of Decimal, works as if they had been designed for ints.

  • Decimal operator + (const DECIMAL& decRHS, const DECIMAL& decLHS)
  • Decimal operator - (const DECIMAL& decRHS, const DECIMAL& decLHS)
  • Decimal operator * (const DECIMAL& decRHS, const DECIMAL& decLHS)
  • Decimal operator / (const DECIMAL& decRHS, const DECIMAL& decLHS)
  • bool operator < (const DECIMAL& decRHS, const DECIMAL& decLHS)
  • bool operator > (const DECIMAL& decRHS, const DECIMAL& decLHS)
  • bool operator <= (const DECIMAL& decRHS, const DECIMAL& decLHS)
  • bool operator >= (const DECIMAL& decRHS, const DECIMAL& decLHS)
  • bool operator == (const DECIMAL& decRHS, const DECIMAL& decLHS)
  • bool operator != (const DECIMAL& decRHS, const DECIMAL& decLHS)

Implementation details

I do not do any arithmetic calculations in my code. I merely use the OLE automation functions for manipulating DECIMALs. All I have done is moulded it all together into a thin C++ wrapper class which makes DECIMALs a bit more enjoyable to work with. Syntactic sugar makes software sweet.

If you take a quick look at the source file you will see that it is a very thin wrapper and adds, to my knowledge, a very small running time overhead. But please, correct me if I am wrong.

Caveat emptor

There are a couple of things which you may be interested in knowing before you use this code.

verify/assert

This code currently uses the C library versions of assert (and my own assert dependent macro verify). You may want to change this before you use this in an ATL or MFC environment. A simple Search and Replace All should do the trick.

Variants

I have not included any method for dealing with VARIANTs. I want a simple and clean interface. If I ever need any interoperability with VARIANTs, I'll add the method. Until then, tough luck - or write it yourself.

Strings

As you may have noticed, I only support BSTR strings in the interface. The reason is quite simple; I intend to use this code in the shadow lands near VB[Script] (and possibly other weird environments) where BSTR is the string of choice. I don't believe in bloating interfaces, so I'll refrain from adding support for any other type of string unless I really need it. If I do, I'll update this source code. If you need it before I do, well, you've got the source!

VC6

I've included VC6 as a keyword for this article. But I admit that I have not tested against that compiler. But since I'm not using any fancy templates or other new and exotic features, I believe this code will work just fine in VC6. In fact, I had an older version of this class in another project, which compiled just fine for VC6. Considering that I've removed a lot of bloat, this class should still compile. This is QA at its peak.

Rounding coins

There's a free function called RoundToSmallestCoin in the header file. It's a function I use in POS-software I write at work. I keep it in this file because I'm lazy. If you feel that it's bloating your code, just select it and hit the delete button.

References

Marc Clifton wrote a similar article about a decimal class. His implementation is perfect if you do not intend to work with COM/OLE automation environments. You can find his article here.

Disclaimer and License grant

Disclaimer

No warranties of any kind comes with this article and source code. I cannot be held liable for damages to data, damages to hardware or injuries. In fact, you cannot hold me liable for anything if you use this source code.

License grant

However, should you find this code useful, and should we ever meet, I will not say "No thank you" should you offer me a beer (preferably a beer of my choice). However, it's not a requirement. This is beerware if it's ok with you, otherwise it's freeware.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here