    <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/">
     <channel>
        <title>ACCU  :: Class Struggle</title>
        <link>https://members.accu.org/index.php/articles/1353</link>
        <description>Professionalism in Programming</description>
        <dc:language>en-us</dc:language> 
        <dc:creator>Administrator</dc:creator> 
        <admin:generatorAgent rdf:resource="http://www.xaraya.org" /> 
        <admin:errorReportsTo rdf:resource="mailto:webeditor@accu.org" />
       <sy:updatePeriod>hourly</sy:updatePeriod>
       <sy:updateFrequency>1</sy:updateFrequency>
       <docs>http://backend.userland.com/rss</docs>




<div class="xar-mod-head"><span class="xar-mod-title">Programming Topics + Overload Journal #2 - Jun 1993</span></div>

<table border="0" cellpadding="1" cellspacing="0">
    <tbody>
    <tr>
        <td valign="top">
            Browse in :
       </td>
       <td valign="top">

                                            <a href="https://members.accu.org/index.php/articles/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c13/">Topics</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c65/">Programming</a>
<br />

                                            <a href="https://members.accu.org/index.php/articles/">All</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c76/">Journals</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c78/">Overload</a>

                     &gt;                         <a href="https://members.accu.org/index.php/articles/c222/">02</a>
<br />

                                            <a href="https://members.accu.org/index.php/articles/c65-222/">Any of these categories</a>

                    -                        <a href="https://members.accu.org/index.php/articles/c65+222/">All of these categories</a>
<br />
</td>
   </tr>
   </tbody>
</table>




<div class="xar-error">
   <p>
 <strong>Note:</strong> when you create a new publication type,
the articles module will automatically use the templates
<em>user-display-[publicationtype].xt</em>
and <em>user-summary-[publicationtype].xt</em>.
If those templates do not exist when you try to preview or display a new article,
you'll get this warning :-)  Please place your own templates in themes/<em>yourtheme</em>/modules/articles . The templates will get the extension .xt there. </p>
</div>
<div class="xar-norm xar-standard-box-padding">
   <h1><strong>Title:</strong>&nbsp;Class Struggle</h1>
<p><strong>Author:</strong>&nbsp;</p>
<p>
<strong>Date:</strong> 30 June 1993 11:58:00 +01:00 or Wed, 30 June 1993 11:58:00 +01:00</p>
<p><strong>Summary:</strong>&nbsp;</p>
<p><strong>Body:</strong>&nbsp;<p>For this instalment of Class Struggle, we are going to put ourselves
in the position of a 'C' programming team about to take the first
tentative step into C++. Our business is foreign trading, and over the
years we have developed a number of libraries to cope with the
handling, conversion and general manipulation of foreign currencies
between various programs that our company has developed.</p>
<p>Due to our inexperience with C++, having only just returned from the
training course, we are anxious to convert all our programs to embrace
the OO paradigm. Our managers, being older and wiser, curb our
enthusiasm, and limit us to producing a single currency class that
should serve the business for the next 10 years. We are constrained
further by the nature of our equipment, which varies from PCs and Macs
through UNIX boxes and Mainframes, and must therefore confine our class
to standard C++ and not to utilise any features specific to our PC
compiler.</p>
<h2>Where do we start?</h2>
<p>The first and most obvious step is to draw up the requirements for
our class. This will involve examining how currency is used in all our
systems, and deciding whether to build a class flexible enough to cater
for all eventualities, or to build a suitable base class, and have
custom derivations from the general base class.</p>
<p>After looking at the current programs, we realise that all the
currency usage has been catered for in our currency handling suite, and
so decide to go for one class which will cater for all. Should anybody
want anything extra-special, they are still able to derive from it.</p>
<h2>The Requirements</h2>
<p>Our requirement of the class can be simply put as &quot;A class that can
represent an international currency, to which we can perform as many of
the operators that mean anything and to have sufficient functions to
allow the class to be universally used in a 'C-like' or C++ environment
throughout our business. The class must also be able to display itself
in an output stream in the correct manner&quot;. This is a bit woolly, but
will do for our purposes.</p>
<h2>Data held by the class</h2>
<ul>
  <li>The currency type, Pounds, Yen etc. This will also double as an
indicator to show that the class is in an invalid state.</li>
  <li>The number of units of the currency, for simplicity sake, we will
represent this as a double number, though a BCD representation would be
more desirable.</li>
</ul>
<h2>The Member Functions required</h2>
<span style="font-weight: bold;">Constructors</span><br>
- Default (&pound;0.00)<br>
- Value only (&pound;value) default to pounds<br>
- Currency Only (?0.00) default to zero whatever currency selected<br>
- Complete (?value) no defaulting - set to value/currency supplied<br>
- Copy Constructor<span style="font-weight: bold;"><br>
Destructor</span><br>
- Not needed but supplied anyway as matter of course<span
 style="font-weight: bold;"><br>
Set value functions</span><br>
- accept complete value/currency, (others could present loopholes)<br>
- accept complete currency/value,<br>
- another currency value<br>
<span style="font-weight: bold;">Convert_to</span><br>
- Changes a currency of object to another currency and preserves it
value on the currency market (i.e. converts $3.00 to 20.00 French
Francs at exchange rates of $1.50 to the Pound Sterling and 10.00
French Francs to the Pound Sterling).<span style="font-weight: bold;"><br>
Percent</span><br>
- returns the required percentage of a value in its current currency
(i.e. state_tax = total_price.percent(6.00); will return $3.00 if the
total_price is $50.00 and 2.52DM if total_price is 42.00DM.<span
 style="font-weight: bold;"><br>
The operators</span><br>
This is a list of the operators that will be overloaded, only those for
which a use can be found will be used.<br>
! used to test if currency is valid (usually after screen input etc.)<br>
+ add two currencies (binary) or as unary plus<br>
- Subtract two currencies or unary minus<br>
* multiply currency by constant or constant by currency<br>
/ divide currency by constant giving currency - note should it behave
differently if the divisor is an integer type? i.e. give integer
quotient.<br>
% divide currency by constant giving remainder in currency<br>
= Assign another currency value, but to KEEP our original currency<br>
() Copy another currency<br>
+= Adds another currency to itself, preserving its currency type also
adds a constant to itself<br>
-= Subtracts another currency from itself, preserving its currency type
also subtracts a constant from itself<br>
*= multiply currency by a constant<br>
/= divide a currency (see division for argument)<br>
%= receive remainder of division<br>
&lt;&lt; Output to a stream<br>
&gt;&gt; Input from a stream<br>
= test two currencies for equality<br>
!= test two currencies for inequality<br>
&lt;= test two currencies for less than or equal to<br>
&gt;= test two currencies for greater than or equal to<br>
&lt; test two currencies for less than<br>
&gt; test two currencies for greater than<br>
++ postfix and prefix required; change by one unit of currency<br>
-- postfix and prefix required; change by one unit of currency<br>
<h2>Other considerations</h2>
<p>It has been realised by the team that a class to represent the
currency types is required. This will need to hold such information as
the Currency symbol, whether the symbol is displayed prefix or postfix,
the current exchange rate and the number of decimal places to which the
currency is normally displayed. This information should be file-based
as it could potentially be updated daily or even minute-by-minute,
depending on the nature of the system.</p>
<p>Note: Most code extracts have been simplified, the complete listings
are provided on the companion disk. In order to keep things simple, the
constness of any of the parameters or member functions has been
ignored, as have a number of efficiency considerations (such as
explicit inlines).</p>
<p>For simplicity sake the currency types are to be implemented as an
array, and use enumerated constants to act as index values of currency
type represented by the array, i.e.</p>
<pre class="programlisting">enum currency_names<br>{ pounds = 0, dollars, yen, francs, lira };</pre>
<p>The public interface for currency type is declared as follows:</p>
<pre class="programlisting">class currency_type<br>{ <br>protected:<br>  ... omitted - no need to know <br>public:<br>  currencytype(void); // default constructor<br>  ~currency_type(void); // destructor<br>  void set(char* symb, double r, int places, <br>           position p = prefix);<br>  currency_type&amp; operator= (currency_type&amp; ct);<br>  char* get_symbol(void);<br>  double get_rate(void);<br>  int get_places(void);<br>  position get_position(void);<br>};</pre>
<p>None of the member functions are difficult to understand. The
constructor has been written so that there are no parameters. This is
because it is only intended to be used in an array, for which no
parameters can be supplied. The set member function is used to store
all the characteristics of the currency, and allocates a space long
enough to hold the currency symbol. This then can be used for
multi-character currency symbols (e.g. &quot;AUS $&quot; for Australian dollars).
The destructor is used to free up the space allocated to the currency
symbol when the currency type goes out of scope. The other member
functions are used to access the internals of the currency type in a
read-only manner.</p>
<h2>Multiple Source Files</h2>
<p>For those not familiar with multiple source file compilations, the
#ifndef CURRTYPE_H statement at the top of the currtype.h file may seem
a little strange. This is to prevent any multiple #includes (and hence
multiple declarations) into any single compile unit. The first time
this file is included into the compilation, the value CURRTYPE_H is not
defined, the pre-processor then defines the value CURRTYPE_H. If any
further attempts to include this file (perhaps as part of a different
header file), the #ifndef statement will not be true and the
pre-processor will jump to its corresponding #endif, which is at the
end of the file.</p>
<p>The other section of pre-processor code that looks a little strange
is:</p>
<pre class="programlisting">#ifndef MAIN_CPP<br>extern<br>#endif<br>currency_type CurrType [<br>#ifdef MAIN_CPP<br>5<br>#endif<br>];</pre>
<p>This is the same as writing</p>
<pre class="programlisting">#ifdef MAIN_CPP <br>currency_type CurrType [5]; <br>#else<br>extern currency_type CurrType[]; <br>#endif</pre>
<p>It makes not a lot of difference how you choose to write it; the
effect is the same. Just before this header file is included in the
main program module, the value MAIN_CPP must be defined, thus making
this a definition rather than an external declaration.</p>
<h2>The Currency Class</h2>
<p>The currency class header and source files can be found on the
companion disk (as currency.h and currency.cpp respectively). Because
of the repetitive nature of many of the overloaded operators, only the
salient points are described here.</p>
<p>In order to save writing the same code twice, a private member
function (setup) has been used to insert values into the currency, this
is called both from constructors and the set function. Any attempt to
give the currency a value other than pounds, dollars, yen, francs or
lira will cause this member function to set the currency to an invalid
value.</p>
<p style="font-weight: bold;">Declaration:</p>
<pre class="programlisting">void setup(currency_names, double);<br>void setup(char*, double);</pre>
<p style="font-weight: bold;">Definition:</p>
<pre class="programlisting">void currency::setup(currency_names c, double d)<br>{<br>  amount = d;<br>  if (c &lt; min_currency_val || <br>      c &gt; max_currency_val)<br>    currencyName = invalid_currency; <br>  else<br>    currencyName = c; <br>}<br><br>void currency::setup(char* c, double d) <br>{<br>  amount = d;<br>  currencyName = test_currency_symbol(c); <br>}</pre>
<p>The definition and declaration have been written in different files
so that the currency header can be sourced into the files that will use
the currency class. The definitions will only need to be compiled once.
These are then linked into the final .EXE file. This avoids the need of
all statements being recompiled for any change in the program, as
happens with a single source file. At least now, the only time the
currency class will be recompiled is if changes are made to
currency.cpp, currency.h or any header file used by this class. The
declaration takes place in the header file.</p>
<p>The definition is in the .CPP file, and requires that the class to
which the member function belongs is specified. This is done with the
scope resolution operator (::) and a function header of this kind would
take the simplified form of:</p>
<pre class="programlisting">&lt;return-type&gt; &lt;class&gt;::&lt;member&gt;(&lt;param&gt;) {}</pre>
<h2>Inline Vs Outline</h2>
<p>In the last Class Struggle, all the functions were declared and
defined at the same time. These functions</p>
<p>are then called implicit in-line functions. The member functions
declared &quot;out-of-line&quot; can be made in-line (explicit in-line) by
prefixing both declaration and definition with the 'inline' keyword.
Thus the previous two functions could have been written</p>
<p style="font-weight: bold;">Declaration:</p>
<pre class="programlisting">inline void setup(currency_names, double);<br>inline void setup(char*, double);</pre>
<p style="font-weight: bold;">Definition:</p>
<pre class="programlisting">inline void currency::setup(currency_names c, double d)<br>{<br>  amount = d;<br>  if (c &lt; min_currency_val || <br>      c &gt; max_currency_val)<br>    currencyName = invalid_currency; <br>  else<br>    currencyName = c; <br>  }</pre>
<pre class="programlisting">inline void currency::setup(char* c, double d)<br>{<br>  amount = d;<br>  currencyName = test_currency_symbol(c); <br>}</pre>
<p>The effect of in-lining the code is to avoid the overhead of a
function call. This is fine for small, often-called functions, but if
too many of the larger functions are inlined, it can result in large
increases in the size of the executable. An inline function behaves
like a real function with respect to scope of variables, arguments
passed and local variables, but in fact could make copies of the
function at every point in your program that the inline function is
used. Why do I say could? According to Bjarne, the inline specifier,
like the register specifier, is a &quot;hint to the compiler&quot; rather than a
dictate. The compiler will decide if it can inline the function, but
loops, other inline function calls and the size of the function can all
affect whether the function will be inline or outline.</p>
<p>The test_currency_symbol() member function will match a currency
symbol supplied with one on the internal currency type array. If a
match is found the function returns the enumerated currency value,
otherwise the invalid currency value is returned.</p>
<p style="font-weight: bold;">Declaration:</p>
<pre class="programlisting">currency_names test_currency_symbol(char*); <br></pre>
<p style="font-weight: bold;">Definition:</p>
<pre class="programlisting">currency_names currency::test_currency_symbol<br>                                    (char* c)<br>{<br>  currency_names result; <br>  for (int i = min_currency_val; <br>       i &lt;= max_currency_val; i++)<br>  { <br>    if(strcmp(CurrType[i].get_symbol(),c)==0)<br>    {<br>      result = (currency_names)i; <br>      return result; <br>    } <br>  } <br>  return invalid_currency;<br>}</pre>
<p>Only one other protected member function has been supplied, and that
is a member to convert an amount from one currency to another. This
would normally have to be done in so many places, that making it a
member function should provide some safety against the conversion being
copied wrongly.</p>
<p style="font-weight: bold;">Declaration:</p>
<pre class="programlisting">double convert(currency_names, currency_names, double);</pre>
<p style="font-weight: bold;">Definition:</p>
<pre class="programlisting">double currency::convert(currency_names from, currency_names to,<br>                         double value)<br>{<br>  return (from!=invalid_currency &amp;&amp; <br>          to!=invalid_currency ? <br>          (value/CurrType[from].get_rate() *<br>                   CurrType[to].get_rate()) <br>          :0.0); <br>}</pre>
<p>We are now at the point where we can start generating all the member
functions and overloaded operators that we need to make our class work.
The functions I find most useful to define first are the constructors
and destructor. In the case of all the constructors, a call to the
protected member function which is overloaded to handle both the
currency index/amount and currency symbol/amount parameters.</p>
<p style="font-weight: bold;">Declaration:</p>
<pre class="programlisting">currency(void);<br>currency(currency_names, double = 0.0);<br>currency(char*, double = 0.0);<br>currency(double, currency_names = default_currency);<br>currency(currency&amp;);</pre>
<p style="font-weight: bold;">Definition:</p>
<pre class="programlisting">currency::currency(void)<br>{<br>  setup(invalid_currency,0.0);<br>}<br><br>currency::currency(currency_names c, double d)<br>{<br>  setup(c,d);<br>}<br><br>currency::currency(char* c, double d)<br>{ <br>  setup(c,d);<br>}<br><br>currency::currency(double d, currency_names c)<br>{<br>  setup(c,d);<br>}<br><br>currency::currency(currency&amp; c)<br>{<br>  setup(c.currencyName,c.amount); <br>}</pre>
<p>The only constructor that may seem slightly strange is the last one.
This is known as the copy constructor and must be defined with a
reference to an object and not as a value of the object. Earlier
compilers will normally provide a default copy constructor, which will
perform a bitwise copy whilst current ones memberwise copy from one
object to another. When the custom copy constructor is provided, the
compiler will not generate a default. The copy constructor must have
the form X::X(X&amp;) or X::X(X&amp;,int=0) etc. The form X::X(X) is
illegal as a recursive loop will be set up where in order to make a
copy of X in order to pass it by value to the copy constructor, the
copy constructor would have to be used, and so on! This format although
illegal in the forthcoming ANSI C++ standard is permitted by some older
versions of Turbo C++.</p>
<p>In many cases the default copy constructor supplied by the compiler
will be adequate. It is essential to remember though that copying a
pointer to somewhere in free store will mean that the area is pointed
to by two pointers. This allows one to delete the memory and the other
to continue to use it, or so that both are modifying the same piece of
memory. In this case the custom copy constructor would be responsible
for allocating its own memory and copying the contents of the other
object's memory to its own allocated memory area.</p>
<p style="font-weight: bold;">Declaration:</p>
<pre class="programlisting">virtual ~currency(void); <br></pre>
<p style="font-weight: bold;">Definition:</p>
<pre class="programlisting">virtual currency::~currency(void) <br>{<br>}</pre>
<p>The destructor does nothing, but will ensure that the destructor of
anything derived from currency will have its destructor called. e.g.</p>
<pre class="programlisting">class upgraded_currency : public currency<br>{<br>public:<br>  ...<br>  ~upgraded_currency() { cout &lt;&lt; &quot;Bye!&quot;;}<br>};<br>void main(void)<br>{<br>  currency* ptr = new upgraded_currency;<br>  delete ptr; <br>}</pre>
<p>If the destructor is not virtual in the base class, the destructor
will not be called for classes derived from it when destroyed via a
pointer to the base class.</p>
<p>The next group of member functions are the overloaded set()
functions. These are numerous as the team would like the order of
parameters to be immaterial; the class is then able to handle
(&quot;&pound;&quot;,40) as well as (40,&quot;&pound;&quot;).</p>
<p style="font-weight: bold;">Declaration:</p>
<pre class="programlisting">currency&amp; set(currency_names, double);<br>currency&amp; set(char*, double);<br>currency&amp; set(double, currency_names);<br>currency&amp; set(double, char*);<br>currency&amp; set(currency&amp;);</pre>
<p style="font-weight: bold;">Definition:</p>
<pre class="programlisting">currency&amp; currency::set(currency_names c, double d)<br>{<br>  setup(c,d);<br>  return (*this); <br>} <br>currency&amp; currency::set(char* c, double d)<br>{<br>  setup(c,d); <br>  return (*this);<br>}<br>currency&amp; currency::set(double d, currency_names c) <br>{<br>  setup(c,d);<br>  return (*this); <br>}<br>currency&amp; currency::set(double d, char* c)<br>{<br>  setup(c,d); <br>  return (*this); <br>}<br>currency&amp; currency::set(currency&amp; c)<br>{<br>  setup(c.currencyName,c.amount);<br>  return (*this); <br>}</pre>
<p>These functions do not differ much from the constructor member
functions, except that they return a reference to themselves. This is
to enable them to be used as intermediates in calculations. Bjarne
Stroustrup went to a lot of trouble when designing C++ to ensure that
user-designed classes could behave in an identical manner to built-ins.
If the members of your class do not return sensible values/references,
they cannot be chained together in the traditional 'C' way. For
example, I may want to use the result of the set in an if statement:</p>
<pre class="programlisting">if (transaction-&gt;set(this_currency) &gt; max_allowed)...</pre>
<p>If the set() member was of a void return type, then this statement
would require multiple statements to accomplish the same task.</p>
<pre class="programlisting">transaction-&gt;set(this_currency); <br>if (*transaction &gt; max_allowed)...</pre>
<p>This can be seen in more benign situations where your C++ classes
would appear not to behave as if they were built-ins in the case of the
equal sign. In the case of a C built-in, it will also return the result
of the equation so that it may be used to chain to other assignments:</p>
<pre class="programlisting">a = b = c = d; <br>&amp;<br>if((a=func())&gt;val) <br>etc.</pre>
<p>The next two overloaded member functions perform the task of
changing the currency of the current object, but without changing its
value (unless an attempt is made to change it to a currency that does
not exist).</p>
<p style="font-weight: bold;">Declaration:</p>
<pre class="programlisting">currency&amp; convert_to(currency_names);<br>currency&amp; convert_to(char*);</pre>
<p style="font-weight: bold;">Definition:</p>
<pre class="programlisting">currency&amp; currency::convert_to(currency_names c)<br>{ <br>  if (c &lt; min_currency_val || c &gt; max_currency_val)<br>    currencyName = invalid_currency; <br>  else<br>  {<br>    amount = convert(currencyName, c, amount); <br>    currencyName = c;<br>  }<br>  return currency(*this);<br>}<br><br>currency&amp; currency::convert_to(char* c)<br>{<br>  return convert_to(test_currency_symbol(c)); <br>}</pre>
<p>Again these member functions return a reference to themselves, so
that they too can be used to chain correctly in statements.</p>
<p>The next member function returns a currency object as opposed to a
reference to the current object. This is because this function does not
modify the value of currency object and needs to build a temporary
currency object to contain the result.</p>
<p style="font-weight: bold;">Declaration:</p>
<pre class="programlisting">currency percent(double);</pre>
<p style="font-weight: bold;">Definition:</p>
<pre class="programlisting">currency currency::percent(double d)<br>{<br>  return currency(currencyName,amount/100.0*d); <br>}</pre>
<p>Because all the data members are protected, and we need some means
of finding out what currency the object represents, it is better to
provide simple member functions to return the desired values, rather
than allow member data items to be public. Should you be tempted to use
the latter technique &quot;because it's easier&quot;, just remember that you have
then lost control of one of your data members. Any torn, dick or harry
will then be able to place incorrect values into this field at any
time. This makes debugging a lot more difficult, and makes it easier
for subtle bugs to exist.</p>
<p style="font-weight: bold;">Declaration:</p>
<pre class="programlisting">currency_names get_currency(void); </pre>
<p style="font-weight: bold;">Definition:</p>
<pre class="programlisting">currency_names currency::get_currency(void) <br>{<br>  return currencyName; <br>}</pre>
<p>It is necessary to be able to test on the status of a currency
before using it. In this scheme I have elected to borrow a technique
used by the stream library. There are two functions (good() and bad())
and the ! and void* operators. It is obvious what the functions do, but
the operators are used as follows:</p>
<pre class="programlisting">if (!currency_val) // if illegal_currency<br>if (currency_val.bad()) // same as above<br>if (currency_val) // if currency_val is a valid currency<br>if (currency_val.good()) // same as above</pre>
<p>The binary plus and minus operators both behave in a similar way to
the percent member function in that they need to create a temporary
object to return to the evaluation in progress.</p>
<p style="font-weight: bold;">Declaration:</p>
<pre class="programlisting">currency operator+(currency&amp;);<br>currency operator-(currency&amp;);</pre>
<p style="font-weight: bold;">Definition:</p>
<pre class="programlisting">currency currency::operator+(currency&amp; a)<br>{<br>  return currency(currencyName, amount + <br>  convert(a.currencyName, currencyName, a.amount));<br>}<br>  <br>currency currency::operator-(currency&amp; s)<br>{<br>  return currency(currencyName,amount -<br>  convert(s.currencyName, currencyName, s.amount)); <br>}</pre>
<p>Unlike their binary counterparts, the unary plus and minus operators
behave in different ways. The unary plus need only return a reference
to itself, whilst the unary negative must create a temporary object of
the same currency as itself, but with the amount negated. The unary
plus and minus (as opposed to binary ones) are signified by a void
parameter list.</p>
<p style="font-weight: bold;">Declaration:</p>
<pre class="programlisting">currency&amp; operator+(void);<br>currency operator-(void);</pre>
<p style="font-weight: bold;">Definition:</p>
<pre class="programlisting">currency&amp; currency::operator+(void)<br>{<br>  return (*this);<br>}</pre>
<pre class="programlisting">currency currency::operator-(void)<br>{<br>  return currency(currencyName, -amount);<br>}</pre>
<p>The multiply operator (to be complete) should be able to cope with 2
forms, the (number * currency) and (currency * number). The latter case
can be written in a similar manner to the binary plus operator. The
latter case, however, requires that we overload the normal multiply
operator. We then need to give this operator access to the internals of
the currency class. This is achieved by making the system multiply
operator a friend of the class. In brief, friends are allowed access to
your private and protected member data/functions in addition to the
public ones. Careful consideration should be given before declaring
friends, as they override the protection set up in the class and used
badly can cause the class to malfunction.</p>
<p>Robert Murray, in his book C++ Strategies and Tactics, claims the
following quote (no name attributed, but you'd recognise the name) <br>
<span style="font-style: italic;">&quot;A friend is someone who can touch
your private parts&quot;</span> -he was of course referring to private
members!</p>
<p>Notice the syntax of the definition of the system multiply operator,
where both values to the left and right of the multiply sign need to be
defined. Also, as this is a system operator being overloaded, it is not
a member of the class and is not a 'currency::operator *' but a plain
'operator *'.</p>
<p style="font-weight: bold;">Declaration:</p>
<pre class="programlisting">currency operator*(double);<br>friend currency operator*(double, currency&amp;);</pre>
<p style="font-weight: bold;">Definition:</p>
<pre class="programlisting">currency currency::operator*(double m)<br>{<br>  return currency(currencyName, m * amount);<br>}<br>currency operator*(double&amp; m, currency&amp; c)<br>{ <br>  return currency(c.currencyName, c.amount*m);<br>}</pre>
<p>There is nothing special about the divide and modulus operators.
Just remember that if you divide by an int, the result is an integer
division and not a rounding of the division by an integer.</p>
<p style="font-weight: bold;">Declaration:</p>
<pre class="programlisting">currency operator/(int);<br>currency operator/(double);<br>currency operator%(int);</pre>
<p style="font-weight: bold;">Definition:</p>
<pre class="programlisting">currency currency::operator/(int d)<br>{<br>  return currency(currencyName, long(amount)/d);<br>}<br>currency currency::operator/(double d)<br>{<br>  return currency(currencyName, amount/d);<br>}<br>currency currency::operator%(int d)<br>{<br>  return currency(currencyName, fmod(amount,d));<br>}</pre>
<p>The assignment (single equal) operator has been designated as 'take
the value of the assignment, but retain our current currency'. This has
the same effect as a copy and then conver_to(). The test 'if (&amp;c !=
this)' is to ensure that in the case where an assignment 'curr1 =
curr1' occurs, no work need be done. In the case of this program, no
harm will be done by omitting the test, but when dynamic memory
allocation is involved, it is possible to delete the data you are about
to assign from. This is a bit involved for Class Struggle, so I'll deal
with it in another edition of Overload.</p>
<p style="font-weight: bold;">Declaration:</p>
<pre class="programlisting">currency&amp; operator=(currency&amp;);</pre>
<p style="font-weight: bold;">Definition:</p>
<pre class="programlisting">currency&amp; currency::operator=(currency&amp; c)<br>{<br>  if (&amp;c != this)<br>  { <br>    if (currencyName == invalid_currency)<br>      set(c.currencyName, c.amount); <br>    else<br>      amount = convert(c.currencyName, <br>               currencyName, c.amount);<br>  }<br>  return *this;<br>}</pre>
<p>The operator() has been overloaded such that it will produce an
exact copy of the currency parameter. It is in effect another
assignment. In some ways this is almost breaking one of the 'golden
rules' where one should not produce any surprises when overloading
operators. I envisage the overload of the operator () as acting in the
same way as a copy constructor. It removes my guilt at possibly
producing a surprise overload.</p>
<p style="font-weight: bold;">Declaration:</p>
<pre class="programlisting">currency&amp; operator()(currency&amp;);</pre>
<p style="font-weight: bold;">Definition:</p>
<pre class="programlisting">currency&amp; currency::operator()(currency&amp; c)<br>{<br>  if (&amp;c != this)<br>    set(c); <br>  return *this; <br>}</pre>
<p>Other operators such as +=, -=, *=, /= and %= all behave in the same
manner as their individual signs, but perform value assignment in the
same manner as the equal sign. The code for these operators can be
found on the companion disk.</p>
<p>The next class of operators that we need to look at are the
increment and decrement operators. These are unary operators, in the
same manner as unary + and unary-, but they can be either postfix or
prefix. The compiler will treat a void parameter list as a prefixed
operator and a single int as a postfix operator. The mechanics of both
prefix and postfix would be expected to be the same, but we must
remember that all our types return either values or references, so that
they may be chained. In order to achieve this, the prefix (done
immediately) can return a reference to itself. The postfix operator,
however, must return an object representing itself before the operation
takes place. Fortunately this is easily achieved as can be seen in the
following section of code:</p>
<p style="font-weight: bold;">Declaration:</p>
<pre class="programlisting">currency&amp; operator++(void);<br>currency operator++(int);<br>currency&amp; operator--(void);<br>currency operator--(int);</pre>
<p style="font-weight: bold;">Definition:</p>
<pre class="programlisting">currency&amp; currency::operator++(void)<br>{<br>  amount++; <br>  return *this;<br>}<br>currency currency::operator++(int)<br>{ <br>  return currency(amount++,currencyName);<br>}<br>currency&amp; currency::operator--(void)<br>{<br>  amount--; <br>  return *this;<br>}<br>currency currency::operator--(int)<br>{<br>  return currency(amount--, currencyName); <br>}</pre>
<p>For our class to be complete we need to be able to compare currency
objects. As I am essentially lazy, I have used the pre-processor to
generate these operators, as they are all so similar.</p>
<p>In order for the comparison to work, both amounts must be in the
same currency. It is also necessary in the test the equality or
inequality checks for one or both currencies being invalid must be
catered for.</p>
<pre class="programlisting">#define TEST(X) (amount X \ <br>convert(c.currencyName,currencyName,c.amount) \ <br>?TRUE:FALSE)</pre>
<p style="font-weight: bold;">Declaration:</p>
<pre class="programlisting">bool operator==(currency&amp;);<br>bool operator!=(currency&amp;);<br>bool operator&lt;=(currency&amp;);<br>bool operator&gt;=(currency&amp;);<br>bool operator&lt;(currency&amp;);<br>bool operator&gt;(currency&amp;);</pre>
<p style="font-weight: bold;">Definition:</p>
<pre class="programlisting">bool currency::operator==(currency&amp; c)<br>{<br>  if (currencyName == invalid_currency &amp;&amp; <br>      c.currencyName == invalid_currency) <br>    return TRUE;<br>  if (currencyName == invalid_currency || <br>      c.currencyName == invalid_currency) <br>    return FALSE; <br>  return TEST(==); <br>}<br><br>bool currency::operator!=(currency&amp; c)<br>{<br>  if (currencyName == invalid_currency &amp;&amp;<br>      c.currencyName == invalid_currency)<br>    return FALSE; <br>  if (currencyName == invalid_currency ||<br>      c.currencyName == invalid_currency)<br>    return TRUE; <br>  return TEST(!=); <br>}</pre>
<p>The final two operators we are overloading are the ostream inserter
and the istream extractor. These will the give users of our class the
ability to input and output currencies in a consistent and predefined
manner. Both of these operators must be set up as friends, as they are
overloading the &lt;&lt; and &gt;&gt; operators of ostream and istream
respectively. Taking the output stream first, the format of the
currency is as follows:</p>
<pre class="programlisting">&lt;Invalid Currency&gt;</pre>
<p>or</p>
<pre class="programlisting">&lt;-&gt;&lt;prefixSymbol&gt;&lt;amountInFixedDecimalPlaces&gt;</pre>
<p>or</p>
<pre class="programlisting">&lt;-&gt;&lt;amountInFixedDecimalPlaces&gt;&lt;postfixSymbol&gt;</pre>
<p style="font-weight: bold;">Declaration:</p>
<pre class="programlisting">friend ostream&amp; operator&lt;&lt;(ostream&amp;, currency&amp;);</pre>
<p style="font-weight: bold;">Definition:</p>
<pre class="programlisting">ostream&amp; operator&lt;&lt;(ostream&amp; os, currency&amp; c)<br>{<br>  if (c.currencyName==invalid_currency)<br>    os &lt;&lt; &quot;&lt;Invalid Currency&gt;&quot;; <br>  else <br>  {<br>    if (c.amount &lt; 0.0)<br>      os &lt;&lt; '-';<br>    if (CurrType[c.currencyName].getpositionQ ==<br>                                          prefix)<br>&nbsp;     os &lt;&lt; CurrType[c.currencyName].get_symbol(); <br>    if (CurrType[c.currencyName].getplacesQ &gt; 0)<br>    {<br>      os &lt;&lt; setiosflags(ios::fixed) <br>         &lt;&lt; setiosflags(ios::showpoint) <br>         &lt;&lt; setprecision(CurrType<br>                 [c.currencyName].get_places()) <br>         &lt;&lt; fabs(c.amount);<br>    } <br>    else<br>    {<br>      os &lt;&lt; long(fabs(c.amount));<br>    }<br>    if (CurrType[c.currencyName].get_position() ==<br>                                           postfix)<br>      os &lt;&lt; CurrType[c.currencyName].get_symbol();<br>  }<br>  return os; <br>}</pre>
<p>The input stream is designed to take a single word (in the
space-separated sense and not just two bytes) and translate that into a
currency if possible. If there is a problem with the translation, the
currency is then set as invalid and can be tested with the ! operator
or bad() member function. The input stream can work from the keyboard,
a text file or a memory stream.</p>
<p>The main part of the analysis is performed by this analyse currency
member function. It will load either the translated value of the
currency or, in the case of a bad currency, set the appropriate state.</p>
<p style="font-weight: bold;">Declaration:</p>
<pre class="programlisting">void analyse_currency (char*);</pre>
<p style="font-weight: bold;">Definition:</p>
<pre class="programlisting">void currency::analyse_currency(char* b)<br>{<br>  char* p = b;<br>  char* q;<br>  double value = 0.0;<br>  int sign = 1;<br>  // is first character + or - sign<br>  if (*p =='-')<br>  { <br>    sign = -l;<br>    p++; <br>  }<br>  else if (*p =='+')<br>    p++;<br>  // there can now follow either a number or a start <br>  // of a character string<br>  q = p;<br>  if(isdigit(*p))<br>  {<br>    value = atof(p) * sign; <br>    // advance to end of number <br>    q += strspn(p,&quot;0123456789.&quot;); <br>    set(q, value);<br>    // if the next statement is commented out, <br>    // the input will *NOT* check which side the <br>    // symbol is entered i.e. $7.95 and 7.95$ will then <br>    // both be acceptable and equivalent <br>    if (good() &amp;&amp; CurrType[currencyName]. <br>                   get_position() != postfix) <br>      set(invalid_currency,0);</pre>
<pre class="programlisting">  } <br>  else<br>  {<br>    // skip string<br>    p = strpbrk(q,&quot;0123456789.&quot;); <br>    // extract number <br>    value = atof(p) * sign; <br>    // set up string <br>    *p = '\0'; <br>    set(q, value);<br>    // If commented out will *N0T* check which side <br>    // the symbol is entered <br>    if (good() &amp;&amp; CurrType[currencyName]. <br>                   get_position() != prefix) <br>      set(invalid_currency,0);<br>  } <br>}</pre>
<p style="font-weight: bold;">Declaration:</p>
<pre class="programlisting">friend istream&amp; operator&gt;&gt;(istream&amp;, currency&amp;);</pre>
<p style="font-weight: bold;">Definition:</p>
<pre class="programlisting">istream&amp; operator&gt;&gt;(istream&amp; is, currency&amp; c)<br>{<br>  char buffer[80];<br>  is &gt;&gt; buffer;<br>  c.analysecurrency(buffer);<br>  return is; <br>}</pre>
<p>That's it for now, I think I've overdone this article a bit. Sorry
it got a bit boring, but there was a lot of basics to cover. I'm not
sure I covered them all in sufficient detail. I'll probably go through
some of the points mentioned in future articles but in the meantime you
know where to write if you have problems!</p></p>
<p><strong>Notes:</strong>&nbsp;</p>
<p><em>More fields may be available via dynamicdata ..</em></p>
</div>
</channel>
</rss>
