/////////////////////////////////////////////////////////////////////
// (C) Michael A Smith 1991-1999 University of Brighton            //
//     http://www.it.brighton.ac.uk/~mas                           //
/////////////////////////////////////////////////////////////////////
// ANSI C++  program                                               //
// Version automatically created  Mon 09 Jul 2001 21:48:34 BST  //
/////////////////////////////////////////////////////////////////////

// Add defined as 
//  add(T, T, T) rather than T add (T,T) 
// Because the return type is not changed in inheritance 

// Note fix for T + 1 
// 3 @templated functions T + T, T + int, int + T 

#include <iostream>

// --------------------------------------------------------------------- 
// Specification of Money 
// --------------------------------------------------------------------- 

// Note the prevention of a converting constructor by using the 
//  @keyword explicit on the constructor for Money 
// 
// However if a constructor is used explicitly then normal assignment 
//  compatible conversions will take place 

#include "t99_type.h"

#ifndef CLASS_MONEY_SPEC
#define CLASS_MONEY_SPEC

class Money {
public:
  explicit Money( const long = 0L, const int = 0 );
  static void add( Money& , Money, Money );
  friend std::ostream& operator << (std::ostream&, const Money);
  long units() const;                 // return the units 
  int hundredths() const;             // return the hundredths 
private:
  long the_credits;                   // In Units 
  int  the_hundredths;                // In Pence 
};

// Definition of @inline methods 
//  As a user of the class you do not want to see these, but ... 

inline Money::Money( const long credits, const int pence )
{
  the_credits = credits; the_hundredths = pence;
}

inline long Money::units() const
{
  return the_credits;
}

inline int Money::hundredths() const
{
  return the_hundredths;
}

#endif

// --------------------------------------------------------------------- 
// Implementation of Money 
// --------------------------------------------------------------------- 

#ifndef CLASS_MONEY_IMP
#define CLASS_MONEY_IMP

void Money::add( Money& res, Money lhs, Money rhs)
{
  res.the_hundredths = lhs.the_hundredths + rhs.the_hundredths;
  res.the_credits    = res.the_hundredths / 100;
  res.the_hundredths = res.the_hundredths % 100;
  res.the_credits    = res.the_credits +
                       lhs.the_credits + rhs.the_credits;
}

std::ostream& operator << ( std::ostream& s, const Money m )
{
  s << "#" << m.units() << "."
    << (m.hundredths() < 10 ? "0" : "" )
    << m.hundredths();
  return s;
}

#endif

// --------------------------------------------------------------------- 
// Forward declaration of classes 
// --------------------------------------------------------------------- 

class Dollars;
class Pounds;
class Francs;

// --------------------------------------------------------------------- 
// Specification of Dollars 
// --------------------------------------------------------------------- 

#ifndef CLASS_DOLLARS_SPEC
#define CLASS_DOLLARS_SPEC

class Dollars : public Money {
public:
  explicit Dollars( const long = 0L, const int = 0 );
  static void set_rate( const double, const double );
  friend std::ostream& operator << (std::ostream&, Dollars);
  operator Pounds() const;        // Conversion operator Pounds 
  operator Francs() const;        // Conversion operator Francs 
private:
  static double the_pounds_rate;  // Pounds rate 
  static double the_franc_rate;   // Franc rate 
};


#endif

// --------------------------------------------------------------------- 
// Specification of Francs 
// --------------------------------------------------------------------- 

// Still has methods missing if want to work in Francs 


#ifndef CLASS_FRANCS_SPEC
#define CLASS_FRANCS_SPEC

class Francs : public Money {
public:
  explicit Francs( const long = 0, const int = 0);
  friend std::ostream& operator << (std::ostream&, Francs);
  static void set_rate( const double, const double );
  operator Dollars() const;       // Conversion operator Francs 
  operator Pounds() const;        // Conversion operator Pounds 
private:
  static double the_pound_rate;   // Pounds rate 
  static double the_dollar_rate;  // Dollar rate 
};

#endif

// --------------------------------------------------------------------- 
// Specification of Pounds 
// --------------------------------------------------------------------- 

#ifndef CLASS_POUNDS_SPEC
#define CLASS_POUNDS_SPEC

class Pounds : public Money {
public:
  static void set_rate( const double, const double );
  explicit Pounds( const long = 0L, const int = 0 );
  operator Dollars() const;       // Conversion operator Dollars 
  operator Francs() const;        // Conversion operator Francs 
  friend std::ostream& operator << ( std::ostream& s, Pounds m );
private:
  static double the_dollar_rate;  // Dollar rate 
  static double the_franc_rate;   // Franc rate 
};

#endif

// --------------------------------------------------------------------- 
// Implementation of Pounds 
// --------------------------------------------------------------------- 

#ifndef CLASS_POUNDS_IMP
#define CLASS_POUNDS_IMP

#define exception Xexception  // Uses name 
#include <math.h>
#define Xexception exception  // Uses name 

double Pounds::the_dollar_rate = 1.0;
double Pounds::the_franc_rate  = 1.0;

Pounds::Pounds( const long pounds, const int pence ) :
     Money( pounds, pence )
{
}

void Pounds::set_rate( const double dollar_rate, const double franc_rate )
{
  the_dollar_rate = dollar_rate;
  the_franc_rate  = franc_rate;
}

Pounds::operator Dollars() const
{
  long pence = (long) floor( the_dollar_rate * hundredths() +
                             the_dollar_rate * units() * 100.0 + 0.5);

  long units = pence / 100;
  pence      = pence % 100;
  return Dollars( units, pence );
}

Pounds::operator Francs() const
{
  long centime = (long) floor( the_franc_rate * hundredths() +
                               the_franc_rate * units() * 100.0 + 0.5 );
  long units = centime / 100;
  centime    = centime % 100;
  return Francs( units, centime );
}

std::ostream& operator << ( std::ostream& s, Pounds m )
{
  s << "L" << m.units() << "."
    << (m.hundredths() < 10 ? "0" : "" )
    << m.hundredths();
  return s;
}

#endif

// --------------------------------------------------------------------- 
// Implementation of Francs 
// --------------------------------------------------------------------- 

#ifndef CLASS_FRANCS_IMP
#define CLASS_FRANCS_IMP

#define exception Xexception  // Uses name 
#include <math.h>
#define Xexception exception  // Uses name 

double Francs::the_dollar_rate = 1.0;
double Francs::the_pound_rate = 1.0;

Francs::Francs(const long francs, const int centime) :
        Money( francs, centime )
{
}

void Francs::set_rate( const double dollar_rate, const double pound_rate )
{
  the_dollar_rate = dollar_rate;
  the_pound_rate  = pound_rate;
}

Francs::operator Dollars() const
{
  long cents = (long) floor( the_dollar_rate * hundredths() +
                             the_dollar_rate * units() * 100.0 + 0.5);

  long dollars = cents / 100;
  cents        = cents % 100;
  return Dollars( dollars, cents );
}

Francs::operator Pounds() const
{
  long pence  = (long) floor( the_pound_rate * hundredths() +
                              the_pound_rate * units() * 100.0 + 0.5 );
  long pounds = pence / 100;
  pence       = pence % 100;
  return Pounds( pounds, pence );
}

std::ostream& operator << ( std::ostream& s, Francs m )
{
  s << "SFr" << m.units() << "."
    << (m.hundredths() < 10 ? "0" : "" )
    << m.hundredths();
  return s;
}

#endif

// --------------------------------------------------------------------- 
// Implementation of Dollars 
// --------------------------------------------------------------------- 

#ifndef CLASS_DOLLARS_IMP
#define CLASS_DOLLARS_IMP

#define exception Xexception  // Uses name 
#include <math.h>
#define Xexception exception  // Uses name 

double Dollars::the_pounds_rate  = 1.0;
double Dollars::the_franc_rate   = 1.0;

Dollars::Dollars( const long dollars, const int cents) :
         Money( dollars, cents )
{
}

void Dollars::set_rate( const double pounds_rate, const double franc_rate )
{
  the_pounds_rate  = pounds_rate;
  the_franc_rate   = franc_rate;
}

std::ostream& operator << ( std::ostream& s, Dollars m )
{
  s << "$" << m.units() << "."
    << (m.hundredths() < 10 ? "0" : "" )
    << m.hundredths();
  return s;
}

Dollars::operator Pounds() const
{
  long pence = (long) floor( the_pounds_rate * hundredths() +
                             the_pounds_rate * units() * 100.0 + 0.5 );
  long pounds = pence / 100;
  pence       = pence % 100;
  return Pounds( pounds, pence );
}

Dollars::operator Francs() const
{
  long centime = (long) floor( the_franc_rate * hundredths() +
                               the_franc_rate * units() * 100.0 + 0.5);
  long francs = centime / 100;
  centime     = centime % 100;
  return Francs( francs, centime );
}

#endif


// --------------------------------------------------------------------- 

template <class Type>
inline Type operator + ( Type lhs, Type rhs )
{
  Type res;
  Type::add( res, lhs, rhs );
  return res;
}

/*

template <class Type1, class Type2>
inline Type1 operator + ( Type1 lhs, Type2 rhs )
{
  Type res;
  Type::add( res, (Type1) lhs, rhs );
  return res;
}
*/


template <class Type>
inline Type operator + ( Type lhs, int rhs )
{
  Type res;
  Type::add( res, lhs, Type(rhs) );
  return res;
}

template <class Type>
inline Type operator + ( int lhs, Type rhs )
{
  Type res;
  Type::add( res, Type(lhs), rhs );
  return res;
}

// --------------------------------------------------------------------- 

#include <iomanip>

// --------------------------------------------------------------------- 

int main1(); int main2(); int main3();
int main4(); int main5(); int main6();
int main7(); int main8(); int main9();
int main10();

int main()
{
  const double Dollar_Pound_rate = 0.6105;   // Dollars -> Pound 
  const double Dollar_Franc_rate = 1.4613;   // Dollars -> Swiss Francs 

  Dollars::set_rate( Dollar_Pound_rate, Dollar_Franc_rate );

  // The money market would have precise rates which would 
  // allow a small profit on conversions 

  const double Pound_Dollar_rate = 1/Dollar_Pound_rate;
  const double Pound_Franc_rate  = Pound_Dollar_rate * Dollar_Franc_rate;

  Pounds::set_rate( Pound_Dollar_rate, Pound_Franc_rate );

  const double Franc_Dollar_rate = 1/Pound_Franc_rate*Pound_Dollar_rate;
  const double Franc_Pound_rate  = 1/Pound_Franc_rate;

  Francs::set_rate( Franc_Dollar_rate, Franc_Pound_rate );

  std::cout << "Example 1 " << "\n"; main1();
  std::cout << "Example 2 " << "\n"; main2();
  std::cout << "Example 3 " << "\n"; main3();
  std::cout << "Example 4 " << "\n"; main4();
  std::cout << "Example 5 " << "\n"; main5();
  std::cout << "Example 6 " << "\n"; main6();
  std::cout << "Example 7 " << "\n"; main7();
  std::cout << "Example 8 " << "\n"; main8();
  std::cout << "Example 9 " << "\n"; main9();
  std::cout << "Example 10" << "\n"; main10();
  return 0;
}

int main1()
{
  std::cout << std::setiosflags( std::ios::fixed );     // Format x.y 
  std::cout << std::setiosflags( std::ios::showpoint ); // 0.10 
  std::cout << std::setprecision(2);                     // 2 dec places 

  std::cout << "Dollars" << "\n";

  Dollars in_dollars(100,00);
  Francs  in_francs;

  in_francs = in_dollars;

  std::cout << "Holiday money = " << in_dollars << "\n";
  std::cout << "Holiday money = " << in_francs << "\n";

  std::cout << "Holiday money = " << in_dollars << "\n";
  std::cout << "Holiday money = " << (Francs) in_dollars << "\n";


  std::cout << "Dollars" << "\n";
  Dollars money_in_dollars( 100, 00 );
  Pounds  money_in_pounds = money_in_dollars;
  Francs  money_in_francs = money_in_dollars;

  std::cout << "Dollars :              " << money_in_dollars << "\n";
  std::cout << "          Francs       " << money_in_francs  << "\n";
  std::cout << "          Pounds       " << money_in_pounds  << "\n";

  std::cout << "Pounds  :              " << money_in_pounds << "\n";
  std::cout << "          Dollars      " << (Dollars) money_in_pounds  << "\n";
  std::cout << "          Francs       " << (Francs)  money_in_pounds  << "\n";


  std::cout << "Francs  :              " << money_in_francs << "\n";
  std::cout << "          Dollars      " << (Dollars) money_in_francs  << "\n";
  std::cout << "          Pounds       " << (Pounds)  money_in_francs  << "\n";

  // 

  money_in_dollars = Dollars(100,00);
  std::cout << "Dollars :              " << money_in_dollars << "\n";
  std::cout << "          Francs       " << money_in_francs  << "\n";
  std::cout << "          Pounds       " << money_in_pounds  << "\n";

  money_in_pounds = Pounds(100,00);
  std::cout << "Pounds  :              " << money_in_pounds << "\n";
  std::cout << "          Dollars      " << (Dollars) money_in_pounds  << "\n";
  std::cout << "          Francs       " << (Francs)  money_in_pounds  << "\n";


  money_in_francs = Francs(100,00);
  std::cout << "Francs  :              " << money_in_francs << "\n";
  std::cout << "          Dollars      " << (Dollars) money_in_francs  << "\n";
  std::cout << "          Pounds       " << (Pounds)  money_in_francs  << "\n";



//Money wrong = 10;              // Does not compile 
  Money mike(10,'a');            // Dubious 
//mike = mike + 1;               // Does not compile GCC 
  return 0;

}

void process();                 // Process monetary transactions 

int main2()
{
  const double Dollar_Pound_rate = 0.6105;   // Dollars -> Pound 
  const double Dollar_Franc_rate = 1.4613;   // Dollars -> Swiss Francs 

  Dollars::set_rate( Dollar_Pound_rate, Dollar_Franc_rate );

  // The money market would have precise rates which would 
  // allow a small profit on conversions 

  const double Pound_Dollar_rate = 1/Dollar_Pound_rate;
  const double Pound_Franc_rate  = Pound_Dollar_rate * Dollar_Franc_rate;

  Pounds::set_rate( Pound_Dollar_rate, Pound_Franc_rate );

  const double Franc_Dollar_rate = 1/Pound_Franc_rate*Pound_Dollar_rate;
  const double Franc_Pound_rate  = 1/Pound_Franc_rate;

  Francs::set_rate( Franc_Dollar_rate, Franc_Pound_rate );

  process();
  return 0;
}

void process()
{
  std::cout << "In Dollars" << "\n";
  Dollars to_pay(100,0);
  std::cout << "Amount to pay  = " << to_pay << "\n";
  std::cout << "Amount to pay  = " << (Pounds) to_pay << "\n";
  std::cout << "Amount to pay  = " << (Francs) to_pay << "\n";

  Dollars discount( 1,0 );

  Dollars sum = Dollars(5,0) + Dollars(5,0);
  Dollars sum2 = to_pay + discount;
  std::cout << sum << "\n";
  std::cout << (Pounds) ( Dollars(5,0) + Dollars(5,0) ) << "\n";
}

int main3()
{
  Money  *mine  = new Money;
  Money  *also  = new Money(1,2);
  Money  *lots  = new Money[10];
  Dollars *yours  = new Dollars;
  Dollars *more   = new Dollars[10];

  *mine = lots[2] = *mine = *also;
  *yours= more[2] = *yours;

  std::cout << "cout << " << *also << "\n";
  std::cerr << "cerr << " << *also << "\n";

  delete mine; delete also; delete [] lots;
  delete yours; delete [] more;

  Money to_spend( 1 , 'A' );      // Type conversion 
/*
  to_spend = 'A';                 // Assignment compatible conversion 
  to_spend = 10L;                 // Assignment compatible conversion 
  to_spend = 10;                  // Assignment compatible conversion 
*/
  return 0;
}

int main4()
{
  Money ham_pizza(4,75);
  Money extra_cheese = Money(0,50);
  Money tuna_pizza = ham_pizza + 1;

  std::cout << "A ham pizza costs " << ham_pizza << "\n";
  std::cout << "A ham pizza with extra cheese costs " <<
            (ham_pizza+extra_cheese) << "\n";
  std::cout << "A tuna pizza costs " << tuna_pizza << "\n";
  return 0;
}

int main5()
{
  Dollars ham_pizza(4,75);
  Dollars extra_cheese = Dollars(0,50);
  Dollars tuna_pizza = ham_pizza + 1;

  std::cout << "A ham pizza costs " << ham_pizza << "\n";
  std::cout << "A ham pizza with extra cheese costs " <<
            (ham_pizza+extra_cheese) << "\n";
  std::cout << "A tuna pizza costs " << tuna_pizza << "\n";
  return 0;
}

int main6()
{
  Dollars old_asset(10,0);
  Dollars new_asset = (Dollars) (Pounds) old_asset;

  std::cout << "old_asset : " << old_asset << "\n";
  std::cout << "new_asset : " << new_asset << "\n";
  std::cout << "Should be the same!!" << "\n";

  Pounds   x1 = (Pounds) old_asset;
  Dollars  x3 = (Dollars) x1;

  std::cout << "Pounds     : " << x1 << "\n";
  std::cout << "Dollars    : " << x3 << "\n";
  return 0;
}


int main7()
{
  std::cout << "In Pounds" << "\n";
  Pounds to_pay(10,0);
  std::cout << "Amount to pay  = " << to_pay << "\n";
  std::cout << "Amount to pay  = " << (Dollars) to_pay << "\n";
  std::cout << "Amount to pay  = " << (Francs) to_pay << "\n";

  Pounds sum = Pounds(5,0) + Pounds(5,0);
  std::cout << sum << "\n";
  std::cout << (Pounds(5,0) + Pounds(5,0)) << "\n";
  return 0;
}

int main8()
{
  Dollars camera(60,50);
  Dollars bag(9,99);

  std::cout << "Cost of camera          : " << camera << "\n";
  std::cout << "Cost of bag             : " << bag << "\n";

  std::cout << "Cost of camera + bag is : ";

  Dollars res; Money::add( res, camera, bag );
  std::cout << res << "\n";
  return 0;
}


int main9()
{
  Dollars camera(60,50);
  Dollars bag(9,99);

  std::cout << "Cost of camera          : " << camera << "\n";
  std::cout << "Cost of bag             : " << bag << "\n";

  std::cout << "Cost of camera + bag is : " << (camera + bag) << "\n";
  return 0;
}

// Neat 
// But ambiguity between type + 1 

template <class Type1, class Type2>
inline Type1 operator + ( Type1 lhs, Type2 rhs )
{
  Type1 res;
  Type1::add( res, lhs, (Type1) rhs );
  return res;
}


int main10()
{
  Dollars camera(60,50);
  Pounds  bag(9,99);

  std::cout << "Cost of camera          : " << camera << "\n";
  std::cout << "Cost of bag             : " << bag << "\n";

  std::cout << "Cost of camera + bag is : " << (camera + bag) << "\n";
  return 0;
}

© M.A.Smith University of Brighton. Created February 1999 Last modified March 1999 Version 1.1
Comments, suggestions, etc. M.A.Smith at brighton dot ac dot uk
[Home page]
Printed / Displayed