スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

F#入門第38回(OOP(3)暗黙的クラス定義(3))

今回のお題は「OOP(3)暗黙的クラス定義(3)」です。
 
まずは宿題の解答例からです。
(宿題)
type Vec2D (x : float,y:float) =
    
    static let mutable m_addCount = 0  
    
    member this.ShowContents ()
                = printfn "x = %f y = %f" x y 
    member this.X = x
    member this.Y = y
      
    member this.Add (t :Vec2D) =
            addCount <- addCount + 1
            new Vec2D(x + t.X,y + t.Y)
    
    static member Vec2DAdd (s:Vec2D,t:Vec2D) =
            addCount <- addCount + 1
            new Vec2D(s.X + t.X,s.Y + t.Y)          
    
    static member AddCountNum =
            m_addCount 
 
上のクラスにインスタンスの個数を表示するプロパティNumOfInstancesを追加してください。
 
(解答例)
 
type Vec2D (x : float,y:float) =
    
    //Primary Constructors ここから
    
    static let mutable m_addCount = 0  
    static let mutable m_numOfInstances = 0
    do m_numOfInstances <- m_numOfInstances + 1
    
    //Primary Constructors ここまで
    
    member this.ShowContents
                = printfn "x = %f y = %f" x y 
    member this.X = x
    member this.Y = y
  
    
    member this.Add (t :Vec2D) =
            m_addCount <- m_addCount + 1
            new Vec2D(x + t.X,y + t.Y)
    
    static member Vec2DAdd (s:Vec2D,t:Vec2D) =
            m_addCount <- m_addCount + 1
            new Vec2D(s.X + t.X,s.Y + t.Y)          
    
    static member AddCountNum =
            m_addCount 
     
     static member NumOfInstances =
            m_numOfInstances
 
Primary Constructorsから、デフォルトのメインコンストラクタが作成されますから、ここで、m_numOfInstancesの値を1増やすように設定しておきます。
 
(使用例)
 
> Vec2D.NumOfInstances ;;
val it : int = 0
 
> let t = new Vec2D (1.0,2.0);;
val t : Vec2D
 
> Vec2D.NumOfInstances ;;
val it : int = 1
 
それでは、今回はアクセス制御の話からです。
F#では、アクセス制御の方法が3通りあります。
 
(1)public メソッドやプロパティはどこからでも可視である。F#では、すべての型、値、関数については、デフォルトでこの設定。
 
(2)private クラス内からのみ可視。
 
(3)internal publicとほぼ同等だが、ただ、同一アセンブリ内からしか見えない。
 
さて、これらのキーワードをどの部分に挿入可能かが次の問題となりますが、、次の例をみてください。
###?###の部分が挿入可能部分です。
 
type ###1### Vec2D ###2###(x : float,y:float) =
    
    //Primary Constructors ここから
    
    static let mutable m_addCount = 0  
    static let mutable m_numOfInstances = 0
    do m_numOfInstances <- m_numOfInstances + 1
    
    //Primary Constructors ここまで
    
    member ###3### this.ShowContents
                = printfn "x = %f y = %f" x y 
    member ###3### this.X = x
    member ###3### this.Y = y
  
    static member ###3### NumOfInstances =
                            m_numOfInstances
 
    ###4### new() = new Vec2D ( 0.0,0.0)
 
上において
###1###はクラス全体に対するアクセス制御
###2###はPrimary Constructorsに対して自動生成されるメインコンストラクタに対するアクセス制御
###3###はプロパティ、メソッドに対するアクセス制御
###4###はコンストラクタに対するアクセス制御
が挿入可能な部分となります。
 
protectedはないのですが、F#ではprotected inheritance(プロテクト継承)で、これを実現します。(継承については、次に説明します。)
 
次は継承(inheritance)です。継承とは大雑把にいうと、現存するクラスに保持するデータ(フィールド)、プロパティ、メソッド等を追加(一部上書き)して、新しいクラスを派生させることです。
暗黙的クラス定義では、フィールドの追加は、クラス定義部分の引数(?)とPrimary Constructorsが作成するメインコンストラクタが重要な役割を果たします。
それでは、例をみてみましょう。
 
type BaseClass (x : int,y:int) =
 
    member this.ShowContents ()
                    = printfn "x = %d y = %d" x y 
    member this.X = x
    member this.Y = y
 
まずは、これにもう一つint型の数を付け加えたクラスを派生させてみます。
 
type DerivedClass (x , y ,z :int) =
    inherit BaseClass(x,y)
    
    member this.Z = z
    
重要なのは、定義の一行目で、inheritキーワードを使い、それに続けて,派生元となるクラスのコンストラクタを呼び出すことです。
 
実行例
 
> let d = DerivedClass (1,2,3);;
val d : DerivedClass
 
> d.Z;;
val it : int = 3
 
> d.X;;
val it : int = 1
 
> d.ShowContents () ;;
x = 1 y = 2
val it : unit = ()
 
この派生クラスに、もうひとつmutableなint型の数を付け加えてみます。
 
type DerivedClass (x , y ,z :int,u:int) =
    inherit BaseClass(x,y)
    let mutable m_u = u
    
    member this.Z = z
    member this.U 
            with get() = m_u
            and set (nu) = m_u <- nu
 
データ(フィールド)、メソッド、プロパティを付け加えることが、できるようになったので、次に、メソッドの上書き方法を紹介します。
まず、次のような原則があります。
「上書きするには、派生元でそのメソッドがabstract宣言されていなければならない。」
たとえば、ShowContentsというメソッドで型がunit -> unitならば
abstract member ShowContents : unit -> unitと宣言します。
これば宣言だけで実装されていない状態です。
また次のような原則があります。
実装されていないabstract宣言されているメソッド(プロパティ)が一つでも存在するクラスは、インスタンス化できない。(このようなクラスを抽象クラスといいます。)さらに、抽象クラスは、クラス定義の直前に[<AbstractClass>]という属性をつけくわえなくてはなりません。
さて次の状態でDerivedClassにおいて、ShowContentsを上書きするにはどうすればいいのでしょうか。
 
type BaseClass (x : int,y:int) =
 
    member this.ShowContents ()
                    = printfn "x = %d y = %d" x y 
    member this.X = x
    member this.Y = y
    
type DerivedClass (x , y ,z :int) =
    inherit BaseClass(x,y)
    
    member this.Z = z
 
一つの解答は、BaseClass内のShowContentsをabstractにして、さらに実装をくわえることです。
これにはキーワードdefaultを使います。
次のようになります。
 
type BaseClass (x : int,y:int) =
 
    abstract member ShowContents :unit -> unit
           default this.ShowContents ()
                    = printfn "x = %d y = %d" x y 
    member this.X = x
    member this.Y = y
 
type DerivedClass (x , y ,z :int) =
    inherit BaseClass(x,y)
    
    override this.ShowContents ()
                = printfn "x = %d y = %d z = %d" x y z 
     
    member this.Z = z
 
派生クラスで、オーバーライドするときは、先頭にoverrideキーワードをつけることが必要なことに留意してください。
 
 
実行例
 
> let t = new DerivedClass(1,2,3);;
val t : DerivedClass
 
> t.ShowContents();;
x = 1 y = 2 z = 3
val it : unit = ()
さらにちょっと細工をして、BaseClassのShowContentsをもっと有効利用できるようにします。
 
type BaseClass (x : int,y:int) =
 
    abstract member ShowContents :unit -> unit
           default this.ShowContents ()
                    = printf "x = %d y = %d " x y 
    member this.X = x
    member this.Y = y
 
type DerivedClass (x , y ,z :int) =
    inherit BaseClass(x,y)
    
    override this.ShowContents ()
                =   base.ShowContents()
                    printf "z = %d \n" z 
     
    member this.Z = z
 
ここでは、DerivedClassのShowContentsでbase.ShowContents()とすることで、派生元のクラスのShowContentsを呼び出して、それに続けて、zだけ表示しています。
 
実行例
 
> let t = new DerivedClass(1,2,3);;
val t : DerivedClass
 
> t.ShowContents();;
x = 1 y = 2 z = 3 
val it : unit = ()
 
次にオーバーライド可能なプロパティをBaseClassに追加してみます。
 
type BaseClass (x : int,y:int) =
 
    abstract  U :int
    default this.U = 0
 
    abstract member ShowContents :unit -> unit
           default this.ShowContents ()
                    = printf "x = %d y = %d " x y 
    member this.X = x
    member this.Y = y
 
type DerivedClass (x , y ,z :int) =
    inherit BaseClass(x,y)
    
    override this.U = 5
    override this.ShowContents ()
                =   base.ShowContents()
                    printf "z = %d \n" z 
     
    member this.Z = z
    
なおこのプロパティにgetterをつけくわえるには、対応箇所を次のように変更します。
   BaseClassでは次に変更
    abstract  U :int with get
    default this.U with get() = 0
   
   DerivedClassでは次に変更
   override this.U with get () = 5
 
また、これ以上派生クラスが定義されるのを許可したくない場合は、クラス定義の直前に[<Sealed>]属性を付け加えます。
 
それでは、宿題です。次の二つのクラスがあります。
 
type BaseClass (x : int,y:int) =
 
    abstract member ShowContents :unit -> unit
           default this.ShowContents ()
                    = printf "x = %d y = %d " x y 
    member this.X = x
    member this.Y = y
 
type DerivedClass (x , y ,z :int) =
    inherit BaseClass(x,y)
    
    override this.ShowContents ()
                =   base.ShowContents()
                    printf "z = %d " z 
     
    member this.Z = z
 
さらに、BaseClassにzを追加してDerivedClassを派生させたように、DerivedClassにuを追加してDerived2Classを派生させてください。
スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

プロフィール

T GYOUTEN

Author:T GYOUTEN
F#と英単語とフリーソフトと読書に興味があります。
ホームページでフリーソフトも公開しています。どぞ御贔屓に。

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
フリーエリア
フリーエリア
blogram投票ボタン
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。