<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>その他</title><link>http://blogs.sqlpassj.org/masatotaniguchi/category/444.aspx</link><description>その他</description><managingEditor>たにぐち</managingEditor><dc:language>ja-JP</dc:language><generator>.Text Version 0.95.2004.102</generator><item><dc:creator>たにぐち</dc:creator><title>Visual Basic 6.0で擬似抽象クラス</title><link>http://blogs.sqlpassj.org/masatotaniguchi/archive/2005/08/13/12756.aspx</link><pubDate>Sat, 13 Aug 2005 04:45:00 GMT</pubDate><guid>http://blogs.sqlpassj.org/masatotaniguchi/archive/2005/08/13/12756.aspx</guid><wfw:comment>http://blogs.sqlpassj.org/masatotaniguchi/comments/12756.aspx</wfw:comment><comments>http://blogs.sqlpassj.org/masatotaniguchi/archive/2005/08/13/12756.aspx#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://blogs.sqlpassj.org/masatotaniguchi/comments/commentRss/12756.aspx</wfw:commentRss><trackback:ping>http://blogs.sqlpassj.org/masatotaniguchi/services/trackbacks/12756.aspx</trackback:ping><description>&lt;P&gt;よく知られている通り、Visual Basic 6.0ではクラスの継承ができません。よって、抽象クラスもないしprotectedというアクセス指定子もありません。VB6プログラマにとって唯一インターフェース継承のみが残されていますが、これも機能は貧弱です。それではVB6プログラマはデザインパターンを意識したプログラミングはあきらめなければならないのでしょうか？&lt;BR&gt;今回は、VB6のインターフェース継承の機能が貧弱であることを逆に利用してVB6で擬似的に抽象クラスを実装してしまおうというお話です。&lt;/P&gt;
&lt;P&gt;インターフェースには本来実装が許されません。しかし、VB6では幸いにも?それができてしまいます。&lt;BR&gt;以下のようなクラスを作成してみました。&lt;BR&gt;&lt;BR&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;' 擬似抽象クラス&lt;BR&gt;' PseudoAbstractClass.cls(クラスモジュール)&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Private m_SubClass As PseudoAbstractClass&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;' 内部変数(本当はprotectedにしたい)&lt;/FONT&gt;&lt;BR&gt;Private m_Message As String&lt;BR&gt;Private m_Count As Integer&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;' 子クラスを保持します&lt;/FONT&gt;&lt;BR&gt;Public Property Set SubClass(value As PseudoAbstractClass)&lt;BR&gt;&amp;nbsp;&amp;nbsp; Set m_SubClass = value&lt;BR&gt;End Property&lt;BR&gt;&lt;BR&gt;Public Sub Release()&lt;BR&gt;&lt;FONT color=#008000&gt;&amp;nbsp;&amp;nbsp; ' 後始末用&lt;BR&gt;&amp;nbsp;&amp;nbsp; ' ここでは実装しない&lt;BR&gt;&lt;/FONT&gt;End Sub&lt;/P&gt;
&lt;P&gt;Public Property Get Message() As String&lt;BR&gt;&amp;nbsp;&amp;nbsp; Message = m_Message&lt;BR&gt;End Property&lt;/P&gt;
&lt;P&gt;Public Property Let Message(value As String)&lt;BR&gt;&amp;nbsp;&amp;nbsp; m_Message = value&lt;BR&gt;End Property&lt;/P&gt;
&lt;P&gt;Public Property Get Count() As Integer&lt;BR&gt;&amp;nbsp;&amp;nbsp; Count = m_Count&lt;BR&gt;End Property&lt;/P&gt;
&lt;P&gt;Public Property Let Count(value As Integer)&lt;BR&gt;&amp;nbsp;&amp;nbsp; m_Count = value&lt;BR&gt;End Property&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;' 擬似abstract関数。子クラスで実装&lt;/FONT&gt;&lt;BR&gt;Public Function SuperClassAbstractFunction() As String&lt;BR&gt;&amp;nbsp;&amp;nbsp; SuperClassAbstractFunction = _&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; m_SubClass.SuperClassAbstractFunction&lt;BR&gt;End Function&lt;/P&gt;
&lt;P&gt;Public Sub SuperClassAbstractSub()&lt;BR&gt;&amp;nbsp;&amp;nbsp; m_SubClass.SuperClassAbstractSub&lt;BR&gt;End Sub&lt;/P&gt;
&lt;P&gt;Public Sub SuperClassSub()&lt;BR&gt;&amp;nbsp;&amp;nbsp; Dim I As Integer&lt;BR&gt;&amp;nbsp;&amp;nbsp; For I = 1 To m_Count&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Debug.Print SuperClassAbstractFunction&lt;BR&gt;&amp;nbsp;&amp;nbsp; Next I&lt;BR&gt;&amp;nbsp;&amp;nbsp; Call SuperClassAbstractSub&lt;BR&gt;End Sub&lt;BR&gt;&lt;BR&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;Visual Basic 6.0ではprotectedアクセス指定子がないので、仕方なくプロパティで代用します。メンバ変数はMessageと、Countです。&lt;BR&gt;もう一つ、m_SubClassという変数があります。プロパティSubClassで取得した子クラスはここに格納されます。擬似抽象メソッドSuperClassAbstractFunction、SuperClassAbstractSubでは、m_SubClassの相当関数を実行します。&lt;STRONG&gt;擬似抽象メソッドは、これを継承したクラスが決定後初めて決まります&lt;/STRONG&gt;。今は入れ物だけです。&lt;/P&gt;
&lt;P&gt;メソッドSuperClassSubですが、ここでは抽象メソッドを使用して何を実行するかが書かれています。ここでは、SuperClassAbstractFunctionの戻り値をm_Count回デバッグウィンドウに表示した後、SuperClassAbstractSubを実行するといった単純なものです。擬似抽象クラスSuperClassAbstractFunctionと、SuperClassAbstractSubが何を行うかまだ決定していないことにご注意ください。&lt;/P&gt;
&lt;P&gt;早速、この擬似抽象クラスを継承した子クラスを作成します。&lt;BR&gt;&lt;BR&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;' 子クラス&lt;BR&gt;&lt;/FONT&gt;&lt;FONT color=#008000&gt;' SubClass1.cls(クラスモジュール)&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Implements PseudoAbstractClass&lt;/P&gt;
&lt;P&gt;Private m_BaseClass As PseudoAbstractClass&lt;/P&gt;
&lt;P&gt;Private Sub Class_Initialize()&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;FONT color=#008000&gt;' 擬似抽象クラスのインスタンスを作り、そのSubClassプロパティに自分を代入する。&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp; Set m_BaseClass = New PseudoAbstractClass&lt;BR&gt;&amp;nbsp;&amp;nbsp; Set m_BaseClass.SubClass = Me&lt;BR&gt;End Sub&lt;BR&gt;&lt;BR&gt;Private Sub PseudoAbstractClass_Release()&lt;BR&gt;&amp;nbsp;&amp;nbsp; &lt;FONT color=#008000&gt;'&amp;nbsp;後始末。使用後、必ず実行する。&lt;BR&gt;&lt;/FONT&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Set m_BaseClass.SubClass = Nothing&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Set m_BaseClass = Nothing&lt;BR&gt;End Sub&lt;/P&gt;
&lt;P&gt;Private Property Set PseudoAbstractClass_SubClass(value As PseudoAbstractClass)&lt;BR&gt;&lt;FONT color=#008000&gt;&lt;FONT color=#000000&gt;&amp;nbsp;&amp;nbsp; &lt;/FONT&gt;' 実装しない&lt;BR&gt;&lt;/FONT&gt;End Property&lt;BR&gt;&lt;BR&gt;Private Property Let PseudoAbstractClass_Message(value As String)&lt;BR&gt;&amp;nbsp;&amp;nbsp; m_BaseClass.Message = value&lt;BR&gt;End Property&lt;BR&gt;Private Property Get PseudoAbstractClass_Message() As String&lt;BR&gt;&amp;nbsp;&amp;nbsp; PseudoAbstractClass_Message = m_BaseClass.Message&lt;BR&gt;End Property&lt;BR&gt;Private Property Let PseudoAbstractClass_Count(value As Integer)&lt;BR&gt;&amp;nbsp;&amp;nbsp; m_BaseClass.Count = value&lt;BR&gt;End Property&lt;BR&gt;Private Property Get PseudoAbstractClass_Count() As Integer&lt;BR&gt;&amp;nbsp;&amp;nbsp; PseudoAbstractClass_Count = m_BaseClass.Count&lt;BR&gt;End Property&lt;/P&gt;
&lt;P&gt;Private Sub PseudoAbstractClass_SuperClassSub()&lt;BR&gt;&amp;nbsp;&amp;nbsp; m_BaseClass.SuperClassSub&lt;BR&gt;End Sub&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;' ここより上は全て共通&lt;BR&gt;' この下よりこのクラスの固有の実装(override)&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Private Function PseudoAbstractClass_SuperClassAbstractFunction() As String&lt;BR&gt;&amp;nbsp;&amp;nbsp; PseudoAbstractClass_SuperClassAbstractFunction = "*****" &amp;amp; m_BaseClass.Message &amp;amp; "*****"&lt;BR&gt;End Function&lt;/P&gt;
&lt;P&gt;Private Sub PseudoAbstractClass_SuperClassAbstractSub()&lt;BR&gt;&amp;nbsp;&amp;nbsp; Debug.Print "******************************" &amp;amp; vbCrLf&lt;BR&gt;&amp;nbsp;&amp;nbsp; Debug.Print "*********" &amp;amp; m_BaseClass.Message &amp;amp; "*********" &amp;amp; vbCrLf&lt;BR&gt;&amp;nbsp;&amp;nbsp; Debug.Print "******************************" &amp;amp; vbCrLf&lt;BR&gt;End Sub&lt;BR&gt;&lt;BR&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;冒頭にImplements PseudoAbstractClassとあります。これで、このクラスのオブジェクトをPseudoAbstractClassのSubClassプロパティに入れることができるようになります。このクラスのInitializeメソッド(コンストラクタ)で、擬似抽象クラスのインスタンスを作り、SubClassプロパティに自分(Me)を代入してしまいます。Message, Countプロパティはそのまま親クラスのものを引き継ぎます。PseudoAbstractClass_SuperClassSubは親クラスのものをそのまま引き継ぐため、m_BaseClassの相当関数を実行します。ここより上は全て共通です。PseudoAbstractClass_SuperClassAbstractFunction、PseudoAbstractClass_SuperClassAbstractSubで、このクラスに固有の実装(override)をします。メッセージに「*」の飾りをつけるだけという簡単なものです。&lt;/P&gt;
&lt;P&gt;「ここより上は全て共通」コメントより上の部分をコピーして、SubClass2.clsというクラスを作り貼り付けます。その下に以下のような関数を作成します。&lt;BR&gt;&lt;BR&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;Private Function PseudoAbstractClass_SuperClassAbstractFunction() As String&lt;BR&gt;&amp;nbsp;&amp;nbsp; PseudoAbstractClass_SuperClassAbstractFunction = "-----" &amp;amp; m_BaseClass.Message &amp;amp; "-----"&lt;BR&gt;End Function&lt;/P&gt;
&lt;P&gt;Private Sub PseudoAbstractClass_SuperClassAbstractSub()&lt;BR&gt;&amp;nbsp;&amp;nbsp; Debug.Print "------------------------------" &amp;amp; vbCrLf&lt;BR&gt;&amp;nbsp;&amp;nbsp; Debug.Print "---------" &amp;amp; m_BaseClass.Message &amp;amp; "---------" &amp;amp; vbCrLf&lt;BR&gt;&amp;nbsp;&amp;nbsp; Debug.Print "------------------------------" &amp;amp; vbCrLf&lt;BR&gt;End Sub&lt;BR&gt;&lt;BR&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;「*」が「-」に変わっただけです(^^;。以下は使用例です。&lt;BR&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;&lt;FONT color=#008000&gt;' Form1.frm(フォームモジュール)&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;Private Sub Command1_Click()&lt;BR&gt;&amp;nbsp;&amp;nbsp; Dim AbstractBaseClass1 As PseudoAbstractClass&lt;BR&gt;&amp;nbsp;&amp;nbsp; Set AbstractBaseClass1 = New SubClass1&lt;BR&gt;&amp;nbsp;&amp;nbsp; AbstractBaseClass1.Message = "継承クラス１"&lt;BR&gt;&amp;nbsp;&amp;nbsp; AbstractBaseClass1.Count = 2&lt;BR&gt;&amp;nbsp;&amp;nbsp; AbstractBaseClass1.SuperClassSub&lt;BR&gt;&amp;nbsp;&amp;nbsp; &lt;FONT color=#008000&gt;' 後始末は必ず実行する&lt;/FONT&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp; AbstractBaseClass1.Release&lt;BR&gt;&amp;nbsp;&amp;nbsp; Dim AbstractBaseClass2 As PseudoAbstractClass&lt;BR&gt;&amp;nbsp;&amp;nbsp; Set AbstractBaseClass2 = New SubClass2&lt;BR&gt;&amp;nbsp;&amp;nbsp; AbstractBaseClass2.Message = "継承クラス２"&lt;BR&gt;&amp;nbsp;&amp;nbsp; AbstractBaseClass2.Count = 3&lt;BR&gt;&amp;nbsp;&amp;nbsp; AbstractBaseClass2.SuperClassSub&lt;BR&gt;&amp;nbsp;&amp;nbsp; AbstractBaseClass2.Release&lt;BR&gt;End Sub&lt;BR&gt;&lt;BR&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;出力は以下の通りです。&lt;BR&gt;
&lt;HR id=null&gt;

&lt;P&gt;&lt;/P&gt;
&lt;P&gt;*****継承クラス１*****&lt;BR&gt;*****継承クラス１*****&lt;BR&gt;******************************&lt;/P&gt;
&lt;P&gt;*********継承クラス１*********&lt;/P&gt;
&lt;P&gt;******************************&lt;/P&gt;
&lt;P&gt;-----継承クラス２-----&lt;BR&gt;-----継承クラス２-----&lt;BR&gt;-----継承クラス２-----&lt;BR&gt;------------------------------&lt;/P&gt;
&lt;P&gt;---------継承クラス２---------&lt;/P&gt;
&lt;P&gt;------------------------------&lt;/P&gt;
&lt;P&gt;
&lt;HR id=null&gt;
&lt;BR&gt;一見、子クラスのメンテが大変のように見えますが、擬似抽象メソッドの実装を除きほとんど共通ですので、一個作成、変更すれば後はコピペでいけます。&lt;BR&gt;基本的な考え方は、親クラスで入れ物を用意しておき、子クラスで入れ物に実装することです。新しい実装がほしくなれば、SubClass1をじゃんじゃんコピーして擬似抽象メソッドの中だけ書き換えればよいわけです。 
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;VBのInterfaceは、一回継承したものを親クラスとしてさらに継承することはできません。その代わり、一度に複数のInterfaceを継承することができます。&lt;/P&gt;
&lt;P&gt;この考え方でVB6で色々なデザインパターンを試してみると面白そうです。できないもの、複雑すぎて実用性のないものも出てくるとは思いますが、「継承」について基本に戻って考えさせてくれる良い機会になるかもしれません。&lt;/P&gt;&lt;img src ="http://blogs.sqlpassj.org/masatotaniguchi/aggbug/12756.aspx" width = "1" height = "1" /&gt;</description></item></channel></rss>