書籍転載
文法からはじめるプログラミング言語Microsoft Visual Basic入門

VB開発者のためのポリモーフィズム(多態性)入門
―第8章 ポリモーフィズム〜クラスの操作方法(前編)―

WINGSプロジェクト 高江 賢(監修 山田 祥寛)
2010/09/22
Page1 Page2

本コーナーは、日経BPソフトプレス発行の書籍『文法からはじめるプログラミング言語Microsoft Visual Basic入門』の中から、特にInsider.NET読者に有用だと考えられる章や個所をInsider.NET編集部が選び、同社の許可を得て転載したものです。基本的に元の文章をそのまま転載していますが、レイアウト上の理由などで文章の記述を変更している部分(例:「上の図」など)や、図の位置などを本サイトのデザインに合わせている部分が若干ありますので、ご了承ください。『文法からはじめるプログラミング言語Microsoft Visual Basic入門』の詳細は「目次情報ページ」もしくは日経BPソフトプレスのサイトをご覧ください。

ご注意:本記事は、書籍の内容を改変することなく、そのまま転載したものです。このため用字用語の統一ルールなどは@ITのそれとは一致しません。あらかじめご了承ください。

 この章では、オブジェクト指向プログラミングを構成する3つの概念の最後、ポリモーフィズムを中心に、オーバーライドのしくみ、抽象クラス、インターフェイスについて説明します。

8.1 ポリモーフィズム(多態性)

 ポリモーフィズム(多態性)とは、同じメソッドを使って、暗黙的にさまざまなインスタンスの動作を切り替えるというものです。といっても、なかなか言葉だけではイメージがつかめないでしょうから、できるだけ具体的なプログラム例を紹介することにします。

 まずは本題に入るまえに、基礎的な(そしてとても重要な)事柄をいくつか説明しましょう。

8.1.1 型変換

 クラスも組み込みデータ型のように、型を変換することができます。ただし継承関係のあるクラスどうしに限ります。

 派生クラスは、基本クラスのメンバを継承しているので、派生クラスでは、基本クラスのメンバを保証していると考えられます。そのため、派生クラスのインスタンスは、基本クラスのインスタンスとしても利用できると見なされます。つまり、基本クラスへ型変換できるということです。この、派生クラスから基本クラスへの変換は、アップキャストと呼ばれ、暗黙的に行うことができます。

 反対に、基本クラスを派生クラスに型変換することをダウンキャストと呼びます。ダウンキャストは、アップキャストのように常にできるとは限りません。そのため、明示的に行う必要があります。

 基本クラスを拡張したものが派生クラスなので、当然、基本クラスをそのまま派生クラスに変換することはできません。

 しかし、派生クラスをいったん基本クラスに変換して、それをまた派生クラスに戻すとしたら、どうでしょうか。

 先ほどのクラス定義を使った、プログラム例を以下に示します。

' 基本クラス
Class Music
  Public Overridable Sub baseInfo()
    Console.WriteLine("Music")
  End Sub
End Class

' 派生クラス
Class Song : Inherits Music

  ' Overridesを付けて同じメソッドを定義
  Public Overrides Sub baseInfo()
    Console.WriteLine("Song")
  End Sub

End Class

' 派生クラス
Class Music2 : Inherits Music

  ' Shadowsを付けて基本クラスのメソッドを隠蔽
  Public Shadows Sub baseInfo()
    Console.WriteLine("Music2")
  End Sub

End Class

Class MainClass
  Public Shared Sub Main()

    ' Songクラスのインスタンスを、Musicクラス型変数に代入
    ' 基本←派生は、常にOK
    Dim m As Music = New Song()

    ' Musicクラス型変数を、Songクラス型に代入
    ' 派生←基本は、明示的なキャストが必要
    Dim s As Song = DirectCast(m, Song)

    ' Musicクラス型変数を、Music2クラスに代入
    ' 文法的にはダウンキャストできる
    ' しかし、元はSongクラスなので、実行時にエラーとなる
    Dim m2 As Music2 = DirectCast(m, Music2)

  End Sub
End Class
[サンプル]castclass.vb

図8-1 型変換

 まずMainメソッドの1行目、Song派生クラスを、Music基本クラスにアップキャストするのは問題ありません。拡張した派生クラスを、元の基本クラスとしてアクセスできます。次は、アップキャストして代入した参照変数mを、DirectCastキーワードを用いて、元のSong派生クラスにダウンキャストしています。DirectCastは、次のような構文で、式をクラスに変換します。なお、2つの引数は継承の関係にあることが必要です。

DirectCast(変数名, 変換後のクラス名)
[構文]DirectCastによるキャスト

 変数mは、元々Song派生クラスだったので、「Dim s As Song = DirectCast(m, Song)」と、Songクラスに変換しても問題はありません。

 では、この基本クラスの参照変数mを、Music2派生クラスにダウンキャストするとどうなるでしょうか。元のクラスは、Song派生クラスなのですが、見かけ上、Music基本クラスへの参照変数mと、Music2派生クラスが継承の関係にあることしかわかりません。そのためコンパイルは成功します。ところがこれを実行すると、変数mの実体がMusic2派生クラスとは異なるので、エラーとなってしまいます。

 このように、いったん基本クラスに変換してしまうと、元のクラスが何であったかがわからない場合があります。それでエラーとなっては困るので、事前に、ダウンキャスト可能かどうかを診断する機能が用意されています。それが、TypeOf...Is式です。

 TypeOf...Is式は、その変数が指定したクラスにダウンキャストできる場合はTrueを返し、そうでないならFalseを返します。構文は、以下のとおりです。

TypeOf 変数名 Is 調べたいクラス名
[構文]TypeOf...Is式

 先ほどのサンプルのMainメソッドを書き換えて、TypeOf...Is式の動作を確かめてみましょう。

Class MainClass
  Public Shared Sub Main()

    Dim m As Music = New Song()
    Dim s As Song = DirectCast(m, Song)

    Console.WriteLine(TypeOf m Is Song)   ' 出力値:True
    Console.WriteLine(TypeOf m Is Music2) ' 出力値:False

  End Sub
End Class
[サンプル]castclass2.vb

 変数mは、Songクラスにダウンキャストできますが、Music2にはできないことがわかります。

 TypeOf...Is式を使う以外に、単純にダウンキャストすることが目的なら、もっと手軽にエラーを回避する方法があります。それには、Visual Basic 2005からサポートされたTryCast演算子を用います。

 TryCast演算子は、変換できるかどうかの判断を行うのではなく、ダウンキャストを行う演算子です。ダウンキャストできれば、その型を返し、できないならNothingを返すという動作になります。

 実行時にエラーとならないので、明示的なダウンキャストを安全に実行できるのです。

 構文は、次のようになります。

TryCast(変数名, クラス名)
[構文]TryCast演算子

 実際のプログラムでは、以下のようになります。

Class MainClass
  Public Shared Sub Main()

    Dim m As Music = New Song()
    Dim s As Song = TryCast(m, Song)

    ' ダウンキャストできないので、Nothingを返す
    Dim m2 As Music2 = TryCast(m, Music2)

    Console.WriteLine(s Is Nothing)  ' 出力値:False
    Console.WriteLine(m2 Is Nothing) ' 出力値:True

  End Sub
End Class
[サンプル]castclass3.vb

8.1.2 オブジェクト型とボックス化

 Visual Basicでは、何も継承していない独立したクラスを定義しても、System名前空間にあるObjectというクラスを継承したと見なされます。

 言い換えればこれは、Visual Basicではどんなクラスでも、基本クラスの元を調べていくと、System.Objectクラスにたどり着くということです。System.Objectクラスが、すべてのクラスの基本クラスになっているのです。

 System.Objectクラスは、単にObjectとしても記述でき、Object型として基本データ型と同様に使用することができます。

 また、Objectクラスには、すべてのクラスに共通するメンバが定義されています。通常、あまり意識する必要のないものですが、いくつかのメソッドは仮想メソッドとして宣言されています。仮想メソッドなのは、派生クラスでオーバーライドされることを見越しているからです*1

*1) Object クラスで定義されているメソッドの中で、ToString メソッドは、最もよく使われるメソッドです。.NET Framework で定義されているクラスでは、各クラスに応じたToString メソッドがオーバーライドされています。

 Objectがすべてのクラスの基本クラスということは、どんなクラスでもObjectにアップキャストすることができる、ということでもあります。

 さらに、参照型であるクラスだけでなく、値型であっても、Objectに変換することができます。このように、値型をObjectに変換することをボックス化(ボクシング)と呼びます。逆に、ボックス化されたObjectを値型に戻すことを、ボックス化解除(アンボクシング)と呼びます。

 ボックス化の概要は、次の図のようになります。数値型変数aをボックス化すると、一時的にメモリ領域が確保され、そこにaの値5がコピーされます。Object型変数には、その領域のアドレスが代入されるというわけです。

図8-2 ボックス化

 では、実際のプログラム例を見てみましょう。

Class MainClass
  Public Shared Sub Main()

    Dim a As Integer = 5      ' 値型の定義
    Dim obj As Object         ' Object型の参照変数
    obj = a                   ' ボックス化

    ' 値型に戻す。ボックス化解除
    Dim b As Integer = DirectCast(obj, Integer)
    Console.WriteLine(b)                      ' 出力値:5

    ' TypeOf...Is式で確かめてみると
    Console.WriteLine(TypeOf obj Is Integer)  ' 出力値:True

    ' 変数objの元はInteger型なので、
    ' DirectCastは実行時にエラーとなる
    Console.WriteLine(TypeOf obj Is Double)   ' 出力値:False
    Dim d As Double = DirectCast(obj, Double)

  End Sub
End Class
[サンプル]box.vb

 integer型変数aをボックス化して、その後、DirectCastを使ってボックス化解除しています。変数bを表示してみると、元のaの値と同じ5になっています。

 DirectCastを用いた、Objectから値型へのボックス化解除は、クラスと同様、元の値型が異なっていれば、実行時にエラーが発生します。その場合、前述のTypeOf...Is式で事前に判断することができます。

 なお、TryCastキーワードは、参照型にしか使えないので、この場合は使用不可です。


 INDEX
  [書籍転載]文法からはじめるプログラミング言語Microsoft Visual Basic入門
  VB開発者のためのポリモーフィズム(多態性)入門
  1.ポリモーフィズムの前提知識
    2.ポリモーフィズムを実現するしくみ

インデックス・ページヘ 「文法からはじめるプログラミング言語Microsoft Visual Basic入門」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間