最新のコンパイラ (@381)では、COMインタフェースが扱えない問題が解消されたようです、まだ試していませんが。よって、もうこの提案も必要なくなりましたが、半端なところで終わらしても仕方がないので、前の話の続きを書き出しておきます。
前提として、次のようなインタフェース、クラスがあるとします。また、前回のようなCastクラス2インタフェースという名の関数が説明上出てきます。
Interface A
Sub ProcA1()
End Interface
Interface AA
Inherits A
Sub ProcA2(n As Long)
End Interface
Interface B
Function ProcB1() As Long
End Interface
Class C
Implements A2, B
Public
' ProcA1, ProcA2, ProcB1のメソッドを実装している
End Class
まずは、コンパイル時には型変換前のオブジェクトの本当の型が静的にはわからない状況への対処法です。
Sub Proc1(o As Object)
Dim a = o As A
End Sub
どうするかというと、クラスCの型情報に、A, AA, Bのインタフェースを実装しているということと、それに対応する変換ルーチン (CastC2A, CastC2AA, CastC2B)へのポインタを保持させます。インタフェースAへのキャスト時には、型情報の中から、このオブジェクトはAを実装しているかどうかを調べ、実装していれば変換ルーチン(CastC2Aへのポインタ)を取り出して、それを呼ぶのです。型情報の構造は知りませんので、このような概念的な話で済ますことにします。
次に、比較演算の話です。
Sub Proc2(c As C)
Dim b1 = c As B
Dim b2 = c As B
このb1とb2は、前回の方法では別の実体になります。つまり、ObjPtr(b1) <> ObjPtr(b2)となり得るのです(最適書き次第でもありますが)。QueryInterfaceなど危ないです。
しかし、AB内では問題ありません。
If Object.ReferenceEquals(b1, b2) Then ...
End Sub
Object.Equalsの引数はObject型インスタンス2つですので、このコードでは、Object.Equalsを呼ぶ際にインタフェースからObjectへの型変換が発生するのです。元が同じインスタンスを指していたのであれば、thisObjは同じオブジェクトを参照するものとなります。結果、ReferenceEqualsは同じオブジェクトへの参照が渡されるので、Trueを返すのです。
あとは、複数インタフェースを実装した場合などの話もありますが、COMではインタフェースの単一継承しか認めていないので、COMを気にせず適当にやれば済みます。
考えていたことはおよそくれくらいです。さて、vtblだけでここまで話を長くなるとは思っていませんでした。逆にそこまでくれば、見慣れたはずのCOMインタフェースがそこまで広げられているということですが。
スポンサード リンク |