RAD Studio |  |

Using a Class to Manage Conversions
Creating the conversion class | Declare variables | Register the conversion family and the other units | Use the new units | See Also
Collapse All

You can always use conversion functions to register a conversion unit. There are times, however, when this requires you to create an unnecessarily large number of functions that all do essentially the same thing.

If you can write a set of conversion functions that differ only in the value of a parameter or variable, you can create a class to handle those conversions. For example, there is a set standard techniques for converting between the various European currencies since the introduction of the Euro. Even though the conversion factors remain constant (unlike the conversion factor between, say, dollars and Euros), you can't use a simple conversion factor approach to properly convert between European currencies for two reasons:

- The conversion must round to a currency-specific number of digits.
- The conversion factor approach uses an inverse factor to the one specified by the standard Euro conversions.

However, this can all be handled by the conversion functions such as the following:
Copy Code

    function FromEuro(const AValue: Double, Factor; FRound: TRoundToRange): Double;
    begin
    Result := RoundTo(AValue * Factor, FRound);
    end;
    function ToEuro(const AValue: Double, Factor): Double;
    begin
    Result := AValue / Factor;
    end;

Copy Code

    double __fastcall FromEuro(const double AValue, const double Factor, TRoundToRange FRound)
    {
    return(RoundTo(AValue * Factor, FRound));
    }
    double __fastcall ToEuro(const double AValue, const double Factor)
    {
    return (AValue / Factor);
    }

The problem is, this approach requires extra parameters on the conversion function, which means you can't simply register the same function with every European currency. In order to avoid having to write two new conversion functions for every European currency, you can make use of the same two functions by making them the members of a class.

Creating the conversion class

The class must be a descendant of TConvTypeFactor. TConvTypeFactor defines two methods, ToCommon and FromCommon, for converting to and from the base units of a conversion family (in this case, to and from Euros). Just as with the functions you use directly when registering a conversion unit, these methods have no extra parameters, so you must supply the number of digits to round off and the conversion factor as private members of your conversion class:

Copy Code

    type
    TConvTypeEuroFactor = class(TConvTypeFactor)
    private
    FRound: TRoundToRange;
    public
    constructor Create(const AConvFamily: TConvFamily;
    const ADescription: string; const AFactor: Double;
    const ARound: TRoundToRange);
    function ToCommon(const AValue: Double): Double; override;
    function FromCommon(const AValue: Double): Double; override;
    end;
    end;

Copy Code

    class PASCALIMPLEMENTATION TConvTypeEuroFactor : public Convutils::TConvTypeFactor
    {
      private:
    TRoundToRange FRound;
    public:
        __fastcall TConvTypeEuroFactor(const TConvFamily AConvFamily,
            const AnsiString ADescription, const double AFactor, const TRoundToRange ARound);
                   TConvTypeFactor(AConvFamily, ADescription, AFactor);
        virtual double ToCommon(const double AValue);
    virtual double FromCommon(const double AValue);
    }

The constructor assigns values to those private members:

Copy Code

    constructor TConvTypeEuroFactor.Create(const AConvFamily: TConvFamily;
    const ADescription: string; const AFactor: Double;
    const ARound: TRoundToRange);
    begin
    inherited Create(AConvFamily, ADescription, AFactor);
    FRound := ARound;
    end;

Copy Code

    __fastcall TConvTypeEuroFactor::TConvTypeEuroFactor(const TConvFamily AConvFamily,
            const AnsiString ADescription, const double AFactor, const TRoundToRange ARound):
                   TConvTypeFactor(AConvFamily, ADescription, AFactor);
    {
      FRound = ARound;
    }

The two conversion functions simply use these private members:

Copy Code

    function TConvTypeEuroFactor.FromCommon(const AValue: Double): Double;
    begin
    Result := RoundTo(AValue * Factor, FRound);
    end;
    function TConvTypeEuroFactor.ToCommon(const AValue: Double): Double;
    begin
    Result := AValue / Factor;
    end;

Copy Code

    virtual double TConvTypeEuroFactor::ToCommon(const double AValue)
    {
      return (RoundTo(AValue * Factor, FRound));
    }
    virtual double TConvTypeEuroFactor::ToCommon(const double AValue)
    {
      return (AValue / Factor);
    }

Declare variables

Now that you have a conversion class, begin as with any other conversion family, by declaring identifiers:

Copy Code

    var
      euEUR: TConvType; { EU euro }
    euBEF: TConvType; { Belgian francs }
    euDEM: TConvType; { German marks }
    euGRD: TConvType; { Greek drachmas }
    euESP: TConvType; { Spanish pesetas }
    euFFR: TConvType; { French francs }
    euIEP: TConvType; { Irish pounds }
    euITL: TConvType; { Italian lire }
    euLUF: TConvType; { Luxembourg francs }
    euNLG: TConvType; { Dutch guilders }
    euATS: TConvType; { Austrian schillings }
    euPTE: TConvType; { Portuguese escudos }
    euFIM: TConvType; { Finnish marks }
      cbEuro: TConvFamily;

Copy Code

    TConvFamily cbEuro;
    TConvType euEUR; // EU euro
    TConvType euBEF; // Belgian francs
    TConvType euDEM; // German marks
    TConvType euGRD; // Greek drachmas
    TConvType euESP; // Spanish pesetas
    TConvType euFFR; // French francs
    TConvType euIEP; // Irish pounds
    TConvType euITL; // Italian lire
    TConvType euLUF; // Luxembourg francs
    TConvType euNLG; // Dutch guilders
    TConvType euATS; // Austrian schillings
    TConvType euPTE; // Protuguese escudos
    TConvType euFIM; // Finnish marks

Register the conversion family and the other units

Now you are ready to register the conversion family and the European monetary units, using your new conversion class. Register the conversion family the same way you registered the other conversion families:

Copy Code

    cbEuro := RegisterConversionFamily ('European currency');

Copy Code

    cbEuro = RegisterConversionFamily ("European currency");

To register each conversion type, create an instance of the conversion class that reflects the factor and rounding properties of that currency, and call the RegisterConversionType method:

Copy Code

    var
      LInfo: TConvTypeInfo;
    begin
      LInfo := TConvTypeEuroFactor.Create(cbEuro, 'EUEuro', 1.0, -2);
      if not RegisterConversionType(LInfo, euEUR) then
        LInfo.Free;
      LInfo := TConvTypeEuroFactor.Create(cbEuro, 'BelgianFrancs', 40.3399, 0);
      if not RegisterConversionType(LInfo, euBEF) then
        LInfo.Free;
      LInfo := TConvTypeEuroFactor.Create(cbEuro, 'GermanMarks', 1.95583, -2);
      if not RegisterConversionType(LInfo, euDEM) then
        LInfo.Free;
      LInfo := TConvTypeEuroFactor.Create(cbEuro, 'GreekDrachmas', 340.75, 0);
      if not RegisterConversionType(LInfo, euGRD) then
        LInfo.Free;
      LInfo := TConvTypeEuroFactor.Create(cbEuro, 'SpanishPesetas', 166.386, 0);
      if not RegisterConversionType(LInfo, euESP) then
        LInfo.Free;
      LInfo := TConvTypeEuroFactor.Create(cbEuro, 'FrenchFrancs', 6.55957, -2);
      if not RegisterConversionType(LInfo, euFFR) then
        LInfo.Free;
      LInfo := TConvTypeEuroFactor.Create(cbEuro, 'IrishPounds', 0.787564, -2);
      if not RegisterConversionType(LInfo, euIEP) then
        LInfo.Free;
      LInfo := TConvTypeEuroFactor.Create(cbEuro, 'ItalianLire', 1936.27, 0);
      if not RegisterConversionType(LInfo, euITL) then
        LInfo.Free;
      LInfo := TConvTypeEuroFactor.Create(cbEuro, 'LuxembourgFrancs', 40.3399, -2);
      if not RegisterConversionType(LInfo, euLUF) then
        LInfo.Free;
      LInfo := TConvTypeEuroFactor.Create(cbEuro, 'DutchGuilders', 2.20371, -2);
      if not RegisterConversionType(LInfo, euNLG) then
        LInfo.Free;
      LInfo := TConvTypeEuroFactor.Create(cbEuro, 'AustrianSchillings', 13.7603, -2);
      if not RegisterConversionType(LInfo, euATS) then
        LInfo.Free;
      LInfo := TConvTypeEuroFactor.Create(cbEuro, 'PortugueseEscudos', 200.482, -2);
      if not RegisterConversionType(LInfo, euPTE) then
        LInfo.Free;
      LInfo := TConvTypeEuroFactor.Create(cbEuro, 'FinnishMarks', 5.94573, 0);
      if not RegisterConversionType(LInfo, euFIM) then
        LInfo.Free;
    end;

Copy Code

    TConvTypeInfo *pInfo = new TConvTypeEuroFactor(cbEuro, "EUEuro", 1.0, -2);
    if (!RegisterConversionType(pInfo, euEUR))
      delete pInfo;
    pInfo = new TConvTypeEuroFactor(cbEuro, "BelgianFrancs", 40.3399, 0);
    if (!RegisterConversionType(pInfo, euBEF))
      delete pInfo;
    pInfo = new TConvTypeEuroFactor(cbEuro, "GermanMarks", 1.95583, -2);
    if (!RegisterConversionType(pInfo, euDEM))
      delete pInfo;
    pInfo = new TConvTypeEuroFactor(cbEuro, "GreekDrachmas", 340.75, 0);
    if (!RegisterConversionType(pInfo, euGRD)
      delete pInfo;
    pInfo = new TConvTypeEuroFactor(cbEuro, "SpanishPesetas", 166.386, 0);
    if (!RegisterConversionType(pInfo, euESP)
      delete pInfo;
    pInfo = new TConvTypeEuroFactor(cbEuro, "FrenchFrancs", 6.55957, -2);
    if (!RegisterConversionType(pInfo, euFFR)
      delete pInfo;
    pInfo = new TConvTypeEuroFactor(cbEuro, "IrishPounds", 0.787564, -2);
    if (!RegisterConversionType(pInfo, euIEP)
      delete pInfo;
    pInfo = new TConvTypeEuroFactor(cbEuro, "ItalianLire", 1936.27, 0);
    if (!RegisterConversionType(pInfo, euITL)
      delete pInfo;
    pInfo = new TConvTypeEuroFactor(cbEuro, "LuxembourgFrancs", 40.3399, -2);
    if (!RegisterConversionType(pInfo, euLUF)
      delete pInfo;
    pInfo = new TConvTypeEuroFactor(cbEuro, "DutchGuilders", 2.20371, -2);
    if (!RegisterConversionType(pInfo, euNLG)
      delete pInfo;
    pInfo = new TConvTypeEuroFactor(cbEuro, "AutstrianSchillings", 13.7603, -2);
    if (!RegisterConversionType(pInfo, euATS)
      delete pInfo;
    pInfo = new TConvTypeEuroFactor(cbEuro, "PortugueseEscudos", 200.482, -2);
    if (!RegisterConversionType(pInfo, euPTE)
      delete pInfo;
    pInfo = new TConvTypeEuroFactor(cbEuro, "FinnishMarks", 5.94573, 0);
    if (!RegisterConversionType(pInfo, euFIM)
      delete pInfo;

Note: The ConvertIt demo provides an expanded version of this example that includes other currencies (that do not have fixed conversion rates) and more error checking.
Use the new units

You can now use the newly registered units to perform conversions in your applications. The global Convert function can convert between any of the European currencies you have registered with the new cbEuro family. For example, the following code converts a value from Italian Lire to German Marks:

Copy Code

    Edit2.Text = FloatToStr(Convert(StrToFloat(Edit1.Text), euITL, euDEM));

Copy Code

    Edit2->Text = FloatToStr(Convert(StrToFloat(Edit1->Text), euITL, euDEM));

See Also

Performing Conversions

Copyright(C) 2009 Embarcadero Technologies, Inc. All Rights Reserved.
What do you think about this topic? Send feedback!