継承多型(Inheritance Polymorphism) は、ベース型から派生型のメンバー手続きを呼び出す機能で、処理されたオブジェクトの実際の型を気にする必要はありません。
序文:
継承多型(サブ型多型)は、さまざまな型を持つことができるエンティティに、単一のインターフェースを提供する、という概念です。
より正確には、同じインターフェイスは、同じ継承階層に属する各型で、同じ識別子を持つメンバー手続きによって、実装されます。
「抽象」/「仮想」手続きのおかげで、派生型手続きを自動的に呼び出すベース型のみを使って、コードを記述できます。
そうすれば、オブジェクトの組み込み型を気にせずに、オブジェクトの手続きを呼び出すことができます。
複数の異なる型に同じ手続き名を使うことで、多型は、はるかに汎用的なプログラミング(抽象化)を可能にします。
コーダーは、ベース手続きを呼び出すときに、手続きが適用されるオブジェクトの正確な型を知る必要はありません。
コーダーは、この型が、手続きを実装することを知っていればよいだけです。
たとえば、手続き 'moving()' は、呼び出し時に参照されたインスタンスの、実際の派生型に従って、適切な移動を実行します。
これにより、プログラムは 'instance' の実際の派生型を心配することなく、 'instance.moving()' と言うことができます。
継承多型の動作
基本型から継承する派生型の手続きを再定義する機能は、特殊化と呼ばれます。
そうすれば、オブジェクトの組み込み型を気にせずにオブジェクトの手続きを呼び出すことができます:
これが、継承多型です。
これにより、基本型の共通インターフェイスでマスクすることで、オブジェクト・ファミリの特殊な型の詳細を抽象化することができます。
ポインター、または基本型の参照を使って、オブジェクトを指定
インスタンス化型が基本型から派生した型であるオブジェクトのコレクションを考えるとき、これらのオブジェクトをすべて基本型のオブジェクトとみなすことで、統一された方法で操作できます。
さらに、特定の動作は、各オブジェクトのインスタンス化された型に応じて、特殊化できます。
つまり、同じ継承階層の異なるオブジェクトの使用は、これらのオブジェクトの動作が特定のままでも、同種です。
したがって、派生型のインスタンスを指す、基本型のポインターまたは参照を使って、このようなオブジェクトを操作できます。
派生型の特殊な手続きにより、ベース型の、抽象/仮想手続きを上書き
型で抽象/仮想手続きを宣言するには、この型が、組み込みの 'Object' 型を、直接または間接的に「拡張」する必要があります。
派生型は、同じ識別子と署名を持つ、つまり、同じ数と型のパラメータ、同じ呼び出し規約、および存在する場合は同じ戻り型(または 参照またはポインタによる戻りのための、派生型の戻り)の手続きを宣言することにより、そのベース型で宣言された抽象/仮想手続きを上書きできます:
- 通常、基本型の参照/ポインターは、この参照/ポインターが基本型から派生したインスタンス化された型のオブジェクトを参照している場合でも、同じ型または階層の上位の型(コンパイル時の静的バインディング)の手続きにのみアクセスできます。
- しかし、基本型手続きが抽象/仮想の場合、これは、実行中のプログラムに、実際のオブジェクト型に関連して、最も派生した上書き手続きを解決するように指示します。(実行時の動的バインディング)
継承多型の内部のメカニズム
抽象/仮想メンバー手続きは、仮想手続きテーブル(vtbl)を使って実装されます。
vtbl は、簡単に言うと、静的手続きポインタのテーブルです。
コンパイラは、各多形の型、つまり、少なくとも抽象/仮想手続きを定義する型、または前者から派生した型、に対して vtbl を埋めます。
vtbl には、継承階層の上位で定義された抽象/仮想手続きを含む、型で使える、すべての抽象/仮想手続きのエントリが含まれます(抽象手続きがまだ実装されていない場合、null ポインタが vtbl に設定されます)。
各 vtbl には、対応する型の各抽象/仮想手続きのための、正しい手続きのアドレスが含まれています。
ここで正しいとは、その手続きを定義/上書きする、最も派生型の対応する手続きのアドレスを意味します。
型がインスタンス化されると、インスタンスには、インスタンス化された型の仮想手続きテーブル(vtbl)へのポインター(vptr)が含められます。
派生型のオブジェクトが、基本型のポインター/参照内で参照されると、抽象/仮想手続き機能が実際に実行されます。
抽象/仮想手続きの呼び出しは、実行時に何らかの形で変換され、対応する手続きが、基になるオブジェクトの型(ポインタ/参照型ではない)の仮想手続きテーブルから、選択されます。
したがって、どの手続きが呼び出されるかは、ポインタ/参照が指す実際のオブジェクトの型に依存します。
これは、コンパイル時にはわかりません。そのため、抽象/仮想手続きコールは、実行時に決定されます。
したがって、(ポインタまたは参照による)抽象/仮想手続きコールは、通常のコールではなく、パフォーマンス・オーバーヘッドが少しあります。
これは、多数のコールがある場合に、巨大になる可能性があります。
抽象/仮想手続きコールは、vptr 値(インスタンス・データのオフセット 0 にある)でアドレス指定された、適切な vtbl を使うことにより、コンパイラによって他の何かに変換されます。
vptr 値の場合、コンパイラーは、型の構築子で、追加のコードを生成します。
これは通常、ユーザーコードの前に追加されます。
ユーザーが構築子を定義しない場合でも、コンパイラーはデフォルトの構築子を生成し、vptr の初期化はそこにあります。
したがって、多形の型のオブジェクトが作成されるたびに、vptr は正しく初期化され、その型の vtbl を指します。
注:
組み込みの 'Object' 型は、'拡張' 宣言を使って、派生したすべての型の RTTI(実行時型情報)収容も提供します。
RTTI 収容は、実行時に、オブジェクトの実際の型を判別できます。
これは、コンパイル時とは異なる場合があります。
RTTI が、オブジェクトの実際の実行時型名だけでなく、'Object' 組み込み型によりその基本型のすべての型名も提供するため、「演算子 Is(rtti)」は、これを使って、オブジェクトがコンパイル時型から派生した型と互換性があるかどうかを確認します。
それにもかかわらず、RTTI によって保存されるこれらの型名(vtbl 内の特定のポインターによって参照される)は、
FreeBASIC キーワードから直接アクセスできない、めちゃくちゃにされた名前です。
制限:
多型は、以下と直接互換性がありません:
- 演算子 'New[]' や 'Delete[]'(配列版の命令文/式/多重定義演算子)。
(実際の型の代わりに)サブタイプ・ポインターを使うと、他の要素(最初の要素を除く)へのアクセスに失敗するため、
- 多重定義演算子 'Delete' でさえ、仮想(静的)として宣言できないため、直接の互換性はありません。
派生型ポインターでこのような演算子 'Delete([])' 命令文を呼び出す代わりに、最も安全な方法は、派生型レベルで演算子 'Delete([])' ステートメントを自動的に起動する、上書きされたユーザー仮想メンバー手続きを(基本型ポインタで)単に呼び出すことです。
例(1).継承多型の学習:「動物型コレクション」
以下に提示する例では、多型のメカニズムに必要なすべての要素を分かりやすく引き出すために、多型の部分が分解されています。
選択される一般的な基本型は、任意の
'animal' (抽象)です。
特殊な派生型は、
'dog',
'cat',
'bird' です(それぞれ、その型名を含む非静的文字列メンバーを定義します)。
汎用の基本型で宣言され、各特殊な派生型で定義する必要がある、抽象手続きは次のとおりです:
- 'addr_override_fct()': インスタンスのアドレスを返します。
- 'speak_override_fct()': 話し方を返します。
- 'type_override_sub()': 型名を出力します(initialyzer を持つ文字列メンバーから)。
- 'animal' 型宣言(一般的な基本型):
- 3つのパブリック抽象手続き(
'addr_override_fct()',
'speak_override_fct()',
'type_override_sub()')が宣言されています(ただし、それらを定義する本体はありません)。
- この基本型は、少なくとも抽象手続きを含むため、インスタンス化できません。
'Base-type animal:
Type animal Extends Object
Public:
Declare Abstract Function addr_override_fct () As animal Ptr
Declare Abstract Function speak_override_fct () As String
Declare Abstract Sub type_override_sub ()
End Type
- 'dog', 'cat', 'bird' 型宣言(特殊な派生型):
- 派生型ごとに、3つの同じパブリック手続き(
'addr_override_fct()',
'speak_override_fct()',
'type_override_sub()')が仮想宣言されており、それらの本体は派生型ごとに特化されています。
- 派生型ごとに、その型名で初期化された非静的文字列メンバー。
- 各派生型は、そのベースで宣言されたすべての抽象手続きを実装するため、インスタンス化可能です。
'Derived-type dog:
Type dog Extends animal
Public:
Declare Virtual Function addr_override_fct () As animal Ptr Override
Declare Virtual Function speak_override_fct () As String Override
Declare Virtual Sub type_override_sub () Override
Private:
Dim As String animal_type = "dog"
End Type
'Derived-type cat:
Type cat Extends animal
Public:
Declare Virtual Function addr_override_fct () As animal Ptr Override
Declare Virtual Function speak_override_fct () As String Override
Declare Virtual Sub type_override_sub () Override
Private:
Dim As String animal_type = "cat"
End Type
'Derived-type bird:
Type bird Extends animal
Public:
Declare Virtual Function addr_override_fct () As animal Ptr Override
Declare Virtual Function speak_override_fct () As String Override
Declare Virtual Sub type_override_sub () Override
Private:
Dim As String animal_type = "bird"
End Type
- 例の完全なコード :
- 多型をトリガーできるようにするために、ベース型のポインター配列(
'animal_list')が宣言され、異なる派生型(犬、猫、鳥)のインスタンスで初期化され、異なる型(ただし、すべてに共通のベース型があります)のオブジェクトのコレクションを構成します。
- したがって、ループ(反復子
'I')に入れられた、同じコンパイル済みコード行は、異なる型(
'animal_list(I)->addr_override_fct()',
'animal_list(I)->speak_override_fct()',
'animal_list(I)->type_override_sub()')のすべてのインスタンスを処理します。これは、多型メカニズムは、実行時に各特殊手続きを呼び出すことができるためです。
'Base-type animal:
Type animal Extends Object
Public:
Declare Abstract Function addr_override_fct () As animal Ptr
Declare Abstract Function speak_override_fct () As String
Declare Abstract Sub type_override_sub ()
End Type
'Derived-type dog:
Type dog Extends animal
Public:
Declare Virtual Function addr_override_fct () As animal Ptr Override
Declare Virtual Function speak_override_fct () As String Override
Declare Virtual Sub type_override_sub () Override
Private:
Dim As String animal_type = "dog"
End Type
'override_sub procedures for dog object:
Virtual Function dog.addr_override_fct () As animal Ptr
Return @This
End Function
Virtual Function dog.speak_override_fct () As String
Return "Woof!"
End Function
Virtual Sub dog.type_override_sub ()
Print This.animal_type
End Sub
'Derived-type cat:
Type cat Extends animal
Public:
Declare Virtual Function addr_override_fct () As animal Ptr Override
Declare Virtual Function speak_override_fct () As String Override
Declare Virtual Sub type_override_sub () Override
Private:
Dim As String animal_type = "cat"
End Type
'override_sub mehods for cat object:
Virtual Function cat.addr_override_fct () As animal Ptr
Return @This
End Function
Virtual Function cat.speak_override_fct () As String
Return "Meow!"
End Function
Virtual Sub cat.type_override_sub ()
Print This.animal_type
End Sub
'Derived-type bird:
Type bird Extends animal
Public:
Declare Virtual Function addr_override_fct () As animal Ptr Override
Declare Virtual Function speak_override_fct () As String Override
Declare Virtual Sub type_override_sub () Override
Private:
Dim As String animal_type = "bird"
End Type
'override_sub mehods for bird object:
Virtual Function bird.addr_override_fct () As animal Ptr
Return @This
End Function
Virtual Function bird.speak_override_fct () As String
Return "Cheep!"
End Function
Virtual Sub bird.type_override_sub ()
Print This.animal_type
End Sub
'Create a dog and cat and bird dynamic instances referred through an animal pointer list:
Dim As dog Ptr p_my_dog = New dog
Dim As cat Ptr p_my_cat = New cat
Dim As bird Ptr p_my_bird = New bird
Dim As animal Ptr animal_list (1 To ...) = {p_my_dog, p_my_cat, p_my_bird}
'Have the animals speak and eat:
Print "INHERITANCE POLYMORPHISM", "@object", "speak", "type"
Print " true operating"
For I As Integer = LBound(animal_list) To UBound(animal_list)
Print " animal #" & I & ":",
Print animal_list(I)->addr_override_fct(), 'real polymorphism
Print animal_list(I)->speak_override_fct(), 'real polymorphism
animal_list(I)->type_override_sub() 'real polymorphism
Next I
Sleep
Delete p_my_dog
Delete p_my_cat
Delete p_my_bird
出力:
INHERITANCE POLYMORPHISM @object speak type
true operating
animal #1: 11086512 Woof! dog
animal #2: 11086584 Meow! cat
animal #3: 11086656 Cheep! bird
例(2).継承多型の学習:「グラフ型コレクション」
以下に提示する例では、多型のメカニズムに必要なすべての要素を分かりやすく引き出すために、多型の部分が分解されています。
選択された一般的な基本型は、2つの描画点と色(抽象化)で定義された 'Graphic Form' です。
特殊な派生型は、'Graphic Line', 'Graphic Box', 'Graphic Circle' です(すべて2つの描画点と色で定義されます):
- 'Graphic Line' は、点1と点2をつなぎます。
- 'Graphic Box' には、向かい合う頂点として、点1(上部の左側)と点2(下部の右側)があります。
- 'Graphic Circle' の中心は点1で、点2を通過します。
汎用ベース型で宣言され、各特殊派生型で定義する必要がある、抽象手続きは、描画ウィンドウでの特殊フォームの画像描画です。
2つの描画点と色は、ジェネリックデータなので、混合物に含まれるジェネリック基本型の、3つのジェネリックデータ項目を誘導します。
'graphic point' 型は、x/y 座標値のカプセル化(プライベートとして宣言)で定義され、プロパティによって(定義された描画画面サイズに応じて)それらの有効性を制御します(ただし、これらは公開されます)。
表記法:
- 一般的な基本型名: 'GraphicForm2P'
- 専門派生型名: 'GraphicLine2P', 'GraphicBox2P', 'GraphicCircle2P'
- 仮想手続き名: 'drawGraphicForm2P()'
- 追加の型名(ジェネリック型内の構成で含む): 'GraphicPoint'
- 'GraphicPoint' 型宣言(汎用ベース型内の構成の追加型):
- 2つの座標(
'_x' と
'_y')はプライベートであり、2つの静的内部関数(
'xValid' と
'yValid')は、描画ウィンドウサイズと比較して、引数として渡された各座標の有効性を返します。
- 各座標には、ユーザー・インターフェイスとして、2つのパブリック・プロパティ(
'x' か
'y')があります。ゲッターと、指定された値の有効性をテストするセッターです。
- パブリックの非デフォルト構築子は、セッターも呼び出して、2つの座標を初期化します。
Type GraphicPoint
Public: '' user interface
Declare Constructor ()
Declare Constructor (Byval x0 As Integer = 0, Byval y0 As Integer = 0)
Declare Property x () As Integer '' x-coordinate getter
Declare Property x (Byval x0 As Integer) '' x-coordinate setter (control if inside open graphic window)
Declare Property y () As Integer '' y-coordinate getter
Declare Property y (Byval y0 As Integer) '' y-coordinate setter (control if inside open graphic window)
Private: '' hidden members
Dim As Integer _x, _y
Declare Static Function xValid (Byval x0 As Integer) As Integer '' x-coordinate inside open graphic window?
Declare Static Function yValid (Byval y0 As Integer) As Integer '' y-coordinate inside open graphic window?
End Type
- 'GraphicForm2P' 型宣言(汎用ベース型):
- 2つのパブリック描画点変数(
'pt1' と
'pt2')およびパブリック色変数(
'col')は、構成ごとにベース型に含まれます。
- パブリック抽象手続き(
'drawGraphicForm2P()')が宣言されています(ただし、これを定義する本体はありません)。
- 基本型はインスタンス化できませんが、保護された構築子はデータ項目を初期化するために定義されています。ただし、各派生型構築子からのみ呼び出されます。
- 独自の解体子を宣言する派生型との互換性を得るために、仮想解体子(空のボディ)が宣言されています(ここでは該当しません)。
この基本型解体子は、基本型ポインタまたは参照で呼び出すことができるようにパブリックです。
Type GraphicForm2P Extends Object '' abstract graphic form defined by two points
Public: '' user interface
Dim As GraphicPoint pt1, pt2
Dim As Integer col
Declare Abstract Sub drawGraphicForm2P () '' request procedure implementation for instantiable derived type
Declare Virtual Destructor () '' for polymorphic compatibility with any derived type
Protected: '' hidden members
Declare Constructor ()
Declare Constructor (Byref p1 As GraphicPoint = Type(0, 0), Byref p2 As GraphicPoint = Type(0, 0), Byval col0 As Integer = 0)
End Type
- 'GraphicLine2P', 'GraphicBox2P', 'GraphicCircle2P' 型の宣言(特殊な派生型):
- 各派生型に対して、同じパブリック手続き(
'drawGraphicForm2P()')が宣言されていますが、その本体は各派生型に特化しています。
- 派生型ごとに、パブリック構築子が宣言され、(ベース構築子を呼び出して)ベースデータ項目を初期化するように定義されています。解体子はありません。これは、この派生型から破壊する特定のものがないためです。
Type GraphicLine2P Extends GraphicForm2P '' graphic line from point 1 to point 2
Public: '' user interface
Declare Constructor (Byref p1 As GraphicPoint = Type(0, 0), Byref p2 As GraphicPoint = Type(0, 0), Byval col0 As Integer = 0)
Declare Sub drawGraphicForm2P () Override '' overridden procedure
End Type
Type GraphicBox2P Extends GraphicForm2P '' graphic box from point 1 to point 2
Public: '' user interface
Declare Constructor (Byref p1 As GraphicPoint = Type(0, 0), Byref p2 As GraphicPoint = Type(0, 0), Byval col0 As Integer = 0)
Declare Sub drawGraphicForm2P () Override '' overridden procedure
End Type
Type GraphicCircle2P Extends GraphicForm2P '' graph circle centered on point1 and passing by point 2
Public: '' user interface
Declare Constructor (Byref p1 As GraphicPoint = Type(0, 0), Byref p2 As GraphicPoint = Type(0, 0), Byval col0 As Integer = 0)
Declare Sub drawGraphicForm2P () Override '' overridden procedure
End Type
-
例の完全なコード:
- 3つの描画点(6つのフォームで使う)が構築されます。
- 多型をトリガーできるようにするため、ベース型ポインター配列(
'pgf')が宣言され、異なる派生型のオブジェクトのコレクションを構成するために、異なる派生型のインスタンスで初期化されます(ただし、すべて共通のベース型を持ちます) 。
- したがって、同じコンパイルされたコード行が、ループに入れられ、異なる型(
'pgf(I)->drawGraphicForm2P()' か
'Delete pgf(I)')のすべてのインスタンスを処理します。多型のメカニズムにより、実行時に、各特殊手続きを呼び出すことができるからです。
Type GraphicPoint
Public: '' user interface
Declare Constructor ()
Declare Constructor (ByVal x0
As Integer =
0,
ByVal y0
As Integer =
0)
Declare Property x
() As Integer '' x-coordinate getter
Declare Property x
(ByVal x0
As Integer) '' x-coordinate setter (control if inside open graphic window)
Declare Property y
() As Integer '' y-coordinate getter
Declare Property y
(ByVal y0
As Integer) '' y-coordinate setter (control if inside open graphic window)
Private: '' hidden members
Dim As Integer _x, _y
Declare Static Function xValid
(ByVal x0
As Integer) As Integer '' x-coordinate inside open graphic window?
Declare Static Function yValid
(ByVal y0
As Integer) As Integer '' y-coordinate inside open graphic window?
End Type
Constructor GraphicPoint
()
End Constructor
Constructor GraphicPoint
(ByVal x0
As Integer =
0,
ByVal y0
As Integer =
0)
This.x = x0
This.y = y0
End Constructor
Property GraphicPoint.x
() As Integer
Return This._x
End Property
Property GraphicPoint.x
(ByVal x0
As Integer)
If GraphicPoint.xValid
(x0
) Then This._x = x0
End Property
Property GraphicPoint.y
() As Integer
Return This._y
End Property
Property GraphicPoint.y
(ByVal y0
As Integer)
If GraphicPoint.yValid
(y0
) Then This._y = y0
End Property
Static Function GraphicPoint.xValid
(ByVal x0
As Integer) As Integer
If ScreenPtr =
0 Then Return 0 '' no open graphic window
Dim As Long w
ScreenInfo(w
)
If x0 >=
0 And x0 <= w -
1 Then Return -
1 Else Return 0
End Function
Static Function GraphicPoint.yValid
(ByVal y0
As Integer) As Integer
If ScreenPtr =
0 Then Return 0 '' no open graphic window
Dim As Long h
ScreenInfo( , h
)
If y0 >=
0 And y0 <= h -
1 Then Return -
1 Else Return 0
End Function
Type GraphicForm2P Extends Object
'' abstract graphic form defined by two points
Public: '' user interface
Dim As GraphicPoint pt1, pt2
Dim As Integer col
Declare Abstract
Sub drawGraphicForm2P
() '' request procedure implementation for instantiable derived type
Declare Virtual
Destructor () '' for polymorphic compatibility with any derived type
Protected: '' hidden members
Declare Constructor ()
Declare Constructor (ByRef p1
As GraphicPoint =
Type(0,
0),
ByRef p2
As GraphicPoint =
Type(0,
0),
ByVal col0
As Integer =
0)
End Type
Virtual
Destructor GraphicForm2P
()
End Destructor
Constructor GraphicForm2P
() '' implementation not absolutely necessary
End Constructor
Constructor GraphicForm2P
(ByRef p1
As GraphicPoint =
Type(0,
0),
ByRef p2
As GraphicPoint =
Type(0,
0),
ByVal col0
As Integer =
0)
This.pt1 = p1
This.pt2 = p2
This.col = col0
End Constructor
Type GraphicLine2P Extends GraphicForm2P
'' graphic line from point 1 to point 2
Public: '' user interface
Declare Constructor (ByRef p1
As GraphicPoint =
Type(0,
0),
ByRef p2
As GraphicPoint =
Type(0,
0),
ByVal col0
As Integer =
0)
Declare Sub drawGraphicForm2P
() Override
'' overridden procedure
End Type
Constructor GraphicLine2P
(ByRef p1
As GraphicPoint =
Type(0,
0),
ByRef p2
As GraphicPoint =
Type(0,
0),
ByVal col0
As Integer =
0)
Base(p1, p2, col0
) '' call the base type constructor
End Constructor
Sub GraphicLine2P.drawGraphicForm2P
()
If ScreenPtr <>
0 Then '' open graphic window
Line (This.pt1.x,
This.pt1.y
)-
(This.pt2.x,
This.pt2.y
),
This.col
End If
End Sub
Type GraphicBox2P Extends GraphicForm2P
'' graphic box from point 1 to point 2
Public: '' user interface
Declare Constructor (ByRef p1
As GraphicPoint =
Type(0,
0),
ByRef p2
As GraphicPoint =
Type(0,
0),
ByVal col0
As Integer =
0)
Declare Sub drawGraphicForm2P
() Override
'' overridden procedure
End Type
Constructor GraphicBox2P
(ByRef p1
As GraphicPoint =
Type(0,
0),
ByRef p2
As GraphicPoint =
Type(0,
0),
ByVal col0
As Integer =
0)
Base(p1, p2, col0
) '' call the base type constructor
End Constructor
Sub GraphicBox2P.drawGraphicForm2P
()
If ScreenPtr <>
0 Then '' open graphic window
Line (This.pt1.x,
This.pt1.y
)-
(This.pt2.x,
This.pt2.y
),
This.col, B
End If
End Sub
Type GraphicCircle2P Extends GraphicForm2P
'' graph circle centered on point1 and passing by point 2
Public: '' user interface
Declare Constructor (ByRef p1
As GraphicPoint =
Type(0,
0),
ByRef p2
As GraphicPoint =
Type(0,
0),
ByVal col0
As Integer =
0)
Declare Sub drawGraphicForm2P
() Override
'' overridden procedure
End Type
Constructor GraphicCircle2P
(ByRef p1
As GraphicPoint =
Type(0,
0),
ByRef p2
As GraphicPoint =
Type(0,
0),
ByVal col0
As Integer =
0)
Base(p1, p2, col0
) '' call the base type constructor
End Constructor
Sub GraphicCircle2P.drawGraphicForm2P
()
If ScreenPtr <>
0 Then '' open graphic window
Dim As Integer r =
Sqr((This.pt2.x -
This.pt1.x
) *
(This.pt2.x -
This.pt1.x
) +
(This.pt2.y -
This.pt1.y
) *
(This.pt2.y -
This.pt1.y
))
Circle (This.pt1.x,
This.pt1.y
), r,
This.col
End If
End Sub
Screen 12 '' open graphic window
Dim As GraphicPoint p1 = GraphicPoint
(320,
240) '' to construct graphic point 1
Dim As GraphicPoint p2 = GraphicPoint
(500,
350) '' to construct graphic point 2
Dim As GraphicPoint p3 = GraphicPoint
(280,
170) '' to construct graphic point 2
'' array of base type pointer referring to instances of different derived types
Dim As GraphicForm2P
Ptr pgf
(...
) =
{New GraphicLine2P
(p1, p2,
14),
New GraphicBox2P
(p1, p2,
13),
New GraphicCircle2P
(p1, p2,
12), _
New GraphicLine2P
(p1, p3,
11),
New GraphicBox2P
(p1, p3,
10),
New GraphicCircle2P
(p1, p3, 09
)}
For I
As Integer =
LBound(pgf
) To UBound(pgf
)
pgf
(I
)->drawGraphicForm2P
() '' accessing dedicated overridden procedure by polymorphism
Next I
For I
As Integer =
LBound(pgf
) To UBound(pgf
)
Delete pgf
(I
) '' accessing dedicated overridden destructor (if necessary) by polymorphism
Next I
Sleep
このコードを実行して、描画出力を確認してください。
参照