二項演算の実装

提供: Appmethod Topics
移動先: 案内検索

クラスを作成してカスタム バリアント型を有効にする への移動


カスタム バリアント型が、標準の二項演算子(System ユニットにリストされている +、-、*、/、div、mod、shl、shr、and、or、xor)と動作するようにするには、BinaryOp メソッドをオーバーライドしなければなりません。 BinaryOp には 3 つのパラメータ --- 左側オペランドの値、右側オペランドの値、および演算子 --- があります。 演算を実行するためにこのメソッドを実装し、左側オペランドを格納していた同じ変数を使用して、結果を返します。

BinaryOpたとえば、次の BinaryOp メソッドは、System.VarCmplx ユニットで定義される TComplexVariantType からきています。

Object Pascal:

 procedure TComplexVariantType.BinaryOp(var Left: TVarData; const Right: TVarData;
   const Operator: TVarOp);
 begin
   if Right.VType = VarType then
     case Left.VType of
       varString:
         case Operator of
           opAdd: Variant(Left) := Variant(Left) + TComplexVarData(Right).VComplex.AsString;
         else
           RaiseInvalidOp;
         end;
       else
         if Left.VType = VarType then
           case Operator of
             opAdd:
               TComplexVarData(Left).VComplex.DoAdd(TComplexVarData(Right).VComplex);
             opSubtract:
               TComplexVarData(Left).VComplex.DoSubtract(TComplexVarData(Right).VComplex);
             opMultiply:
               TComplexVarData(Left).VComplex.DoMultiply(TComplexVarData(Right).VComplex);
             opDivide:
               TComplexVarData(Left).VComplex.DoDivide(TComplexVarData(Right).VComplex);
             else
               RaiseInvalidOp;
           end
         else
           RaiseInvalidOp;
     end
   else
     RaiseInvalidOp;
 end;

この実装では、いくつか注意すべき点があります:

このメソッドは、演算子の右側にあるバリアントが、複素数を表すカスタム バリアントである場合にのみ、処理を行います。 もし左側オペランドが複素数バリアントで、右側オペランドがそうでない場合、複素数バリアントはまず、右側オペランドを複素数バリアントに強制キャストします。 これは、RightPromotion メソッドをオーバーライドし、常に VarType プロパティに型を要求するようにすることで行われます:

Object Pascal:

 function TComplexVariantType.RightPromotion(const V: TVarData;
 const Operator: TVarOp; out RequiredVarType: TVarType): Boolean;
 begin
   { Complex Op TypeX }
   RequiredVarType := VarType;
   Result := True;
 end;

加算演算子は、文字列と複素数に対して実装されており(複素数値を文字列にキャストし連結する)、また、加算、減算、乗算、除算の各演算子は、2 つの複素数に対しても実装されており、その際には、複素数バリアントのデータに格納される TComplexData オブジェクトの各メソッドを使用します。 これは、TVarData レコードを TComplexVarData レコードにキャストし、その VComplex メンバーを使用することにより、アクセスすることができます。

これ以外の演算子や型の組み合わせを行おうとすると、メソッドは RaiseInvalidOp メソッドを呼び出し、ランタイム エラーが発生します。 TCustomVariantType クラスは、数多くのユーティリティ メソッド(RaiseInvalidOp など)を保有しており、カスタム バリアント型の実装から使用することができます。

BinaryOp は、限られた数の型 --- 文字列、および、その他の複素数バリアント -- しか処理しません。 しかし、複素数と他の数値型との間で、演算を実行することは可能です。 BinaryOp メソッドを機能させるには、値をこのメソッドに渡す前に、オペランドを複素数バリアントにキャストしなければなりません。 左側オペランドが複素数の場合、RightPromotion メソッドを使用して、右側オペランドを強制的に複素数バリアントにする方法については、すでに見てきました。 同様のメソッド、LeftPromotion が、右側オペランドが複素数の場合に、左側オペランドを強制的にキャストします。

Object Pascal:
function TComplexVariantType.LeftPromotion(const V: TVarData; const Operator: TVarOp; out RequiredVarType: TVarType): Boolean;
 begin
   { TypeX Op Complex }
   if (Operator = opAdd) and VarDataIsStr(V) then
     RequiredVarType := varString
   else
     RequiredVarType := VarType;
   Result := True;
 end;

この LeftPromotion メソッドは、左側オペランドを別の複素数バリアントに強制的にキャストします。ただし、左側オペランドが文字列で、演算が加算の場合は、LeftPromotion はオペランドを文字列のままにします。

関連項目