Visual Basic 初級講座 |
Visual Basic 中学校 > 初級講座 >
第9回 クラスの使い方
VBではクラスを使わないでプログラムすることはできません。クラスには大変強力ないくつかの機能があるので熟練のプログラマほどクラスの使い方が上手です。逆に下手な使い方をするとプログラムの質は極端に低下します。
今回は今までもところどころで出てきた「クラス」の説明をまとめて、使い方に絞って解説します。クラスを作る場合の説明は別の機会にする予定です。
この回の要約 ・クラスは名前空間によって分類されている。 ・クラスのメンバの呼び出し方はそのメンバが共有メンバなのか非共有メンバなのかによって異なる。 ・クラスのインスタンスを作成する方法 |
今回はプログラムのサンプルなどはごく簡単なものがいくつか登場する程度です。コーヒーなどを飲みながら、くつろいで読んでもらえると幸いです。
クラスについて正面から説明し始めると私の手には負えなくなりますので、ここでは初級者がクラスを使う場合に限って説明しますが、クラスとは便利な機能を持っている「物」です。
クラスは人間にとってわかりやすいように現実世界の「物」に近いように設計されています。たとえば、線を描くときの色や太さを制御するのはPenクラス、つまり「ペン」でしたし、色を塗るにはBrushクラスつまり「筆(ブラシ)」を使います。
他にもButtonクラスなどは現実の「ボタン」と同じように押せばへこむようにできています。
もちろんプログラムの世界には現実世界にないものやどうしても現実世界のものと似せられないものもあるので全部が全部この調子とはいきませんが、基本的にクラスは人間がプログラムの世界になじめるように設計されていると考えてよいです。
VBやC#などのいわゆる.NET言語では、このクラスの機能を利用してプログラムしていきます。たとえば、フォームはクラスですし、ボタンやテキストボックス、ラベルもクラスです。文字列(String)や、数値(Integer, Decimal等)など目に見えないクラスもたくさんあります。
構造体もこのページで扱っている範囲内ではクラスと同じです。扱い方が違うだけです。
今まで入門講座や初級講座で出てきたいくつかのクラスと構造体を並べてみます。この表に登場する「名前空間」についてはすぐ次の章で説明します。
クラス・構造体名 | 性質 | 名前空間 |
Form | クラス | System.Windows.Forms |
Button | クラス | System.Windows.Forms |
Label | クラス | System.Windows.Forms |
TextBox | クラス | System.Windows.Forms |
Color | 構造体 | System.Drawing |
String | クラス | (System) |
Decimal | 構造体 | (System) |
Integer | 構造体 | (System) |
Graphics | クラス | System.Drawing |
Pen | クラス | System.Drawing |
Brush | クラス | System.Drawing |
■表1:クラス・構造体と名前空間
博士のワンポイントレッスン
|
クラスを分類するために「名前空間」またの名を「ネームスペース」という考え方が使われています。
クラスと名前空間の関係は、ファイルとフォルダの関係に似ています。フォルダの中にフォルダをつくれるように、名前空間がまた別の名前空間に属しているという関係が多々あります。
あらかじめ用意されているクラスや構造体がいくつあるのかは知りませんが、ざっとMSDNライブラリを眺めた感じではどう見ても100個以上はあります。多分数百個というところでしょうか?あるいは1000を越えているかもしれません。
またこの他に自分でいろいろなクラスを作ったり、マイクロソフト社以外の企業が作ったクラスを利用することなども考えると、クラスの全貌(ぜんぼう)を把握することは困難です。
名前空間はクラスを分類することによってこの助けをしてくれます。逆に名前空間はクラスを分類する以外の働きはありません。
たとえば、表1に出てくるクラスのうち、FormやButton、Label、TextBoxの名前空間は「System.Windows.Forms」です。この名前空間にはパソコン上で実行するアプリケーションの外観に関するクラスが分類されています。確かにFormもButtonもLabelもTextBoxも目に見えるクラスですよね? (余談ですが目に見えるクラスのことを「コントロール」と呼びます。)
他にはColor, Graphics, Pen ,Brushは「System.Drawing」(読み方:Drawing = ドロゥイング)という名前空間に分類されています。この名前空間はグラフィックスに関する基本的な機能を持ったクラスが分類されています。
名前空間がプログラムをする上で重要なのは、クラスのフルネームを表すのに使用するからです。
たとえば、Color構造体のフルネームは System.Drawing.Color です。これを使ってフォームの背景色を変更するプログラムを書くと次のようになります。
Private
Sub
Button1_Click(ByVal
sender As
System.Object, ByVal
e As
System.EventArgs) Handles
Button1.Click Me.BackColor = System.Drawing.Color.Red End Sub |
■リスト1:Color構造体をフルネームで使用する。
もちろん、実際には System.Drawing.Color.Red のように長々しく書かなくても Color.Red と書いておけば大丈夫です。これはVBが基本的にSystem.Drawing名前空間を参照するように構成されているからです。
VBでは特に何も設定しなくても次の名前空間は自動的に参照されます。
自動的に参照される名前空間 |
Microsoft.VisualBasic |
System |
System.Collection |
System.Data |
System.Diagnostics |
System.Drawing |
System.Windows.Forms |
■表1:既定で参照される名前空間
この設定は[プロジェクト]メニューの[(プロジェクト名)のプロパティ]をクリックして表示されるダイアログ画面で[共通プロパティ] - [インポート] を選択して変更することができます。
■画像1:インポートの設定
ここで設定されていない名前空間のクラスを使う場合には、クラス名を常にフルネームで書くか、プログラム文にImports文を書く必要があります。
Importsステートメントで指定された名前空間はそのファイル内では自動で参照されるようになります。たとえば、System.IO名前空間(読み方:IO = アイオー)のFileクラスのCopyメソッドを使うには次の3通りの呼び出し方があります。
1.フルネームで呼び出す方法
System.IO.File.Copy("C:\Test1.txt", "C:\Copy1.txt")
2.System名前空間だけ省略して呼び出す方法(System名前空間は自動的に参照されているので省略可能です。)
IO.File.Copy("C:\Test1.txt", "C:\Copy1.txt")
3.Importsステートメントを使う方法
Imports System.IO (中略)
File.Copy("C:\Test1.txt", "C:\Copy1.txt")
■リスト2:Importsステートメントで指定した名前空間は省略可能となる。
ファイルの先頭でImportsで宣言した名前空間はそのファイル内では省略可能となります。頻繁に使う名前空間はImportsで指定しておくと良いでしょう。
さて、具体的にクラスを使うにはクラスのメソッドやプロパティを使えばよいということは既にご存知でしょう。
では本やヘルプを見て便利なクラスを発見したとします。たとえば、円周率を取得するにはMathクラスのPIプロパティ(読み方:PI = パイ) を使えばよいということを発見したとすると、もうそれだけで次のように円周率を表示させるプログラムを書くことができます。
※注:円周率は 3.1415926…と無限に続く小数ですが、VB上では当然有限です。とはいってもかなり細かい値まで保持しているので実務計算では支障ありません。
MsgBox(Math.PI) |
■リスト3:円周率を表示する。
これは、もっとも単純な形でのクラスの使用例です。
次に、ファイルサイズを取得するにはFileInfoクラス(読み方:FileInfo = ファイルインフォ)のLengthプロパティを使えばよいということを発見したとしましょう。ところが、今度は次のように書くとビルドエラーになります。
'この例はエラーになります MsgBox(IO.FileInfo.Length) |
■リスト4:プロパティの呼び出し方が間違っている例
考えてみたらどのファイルのサイズを調べようとしているのか指定していないのでエラーになるのは肯けるのですが、この例とMathクラスのPIプロパティを使う例とは「形式的な部分はまったく同じ」という点に注意してください。
つまり、同じようにクラスのプロパティを使う場合でも クラスによって使い方が違う ということです。
また同じクラスでも プロパティによって使い方が違う 場合もあります。
今回はこの「クラスによる違い」をしっかり理解したうえで、種類別にクラスの使い方を習得していただくことが目標です。
章を改めて説明しましょう。
今、プロパティによって使い方が変わると説明しましたが、プロパティだけでなくメソッドでも同じことが言えますので、「メンバによって使い方が違う」と言い換えておきます。
→メソッドやプロパティのことをまとめて「メンバ」と呼びます。
クラスのメンバには使い方の観点から共有メンバと非共有メンバの2種類があります。
共有メンバ | クラス名.メンバ名の形で使用できる。 インスタンス名.メンバ名の形でも使用できる。 |
非共有メンバ | インスタンス名.メンバ名の形でのみ使用できる。 |
■表3:共有メンバと非共有メンバ
前の例で言うと、MathクラスのPIプロパティは共有メンバなのでそのまま Math.PI と書くことができましたが、FileInfoクラスのLengthプロパティは非共有メンバなのでFileInfo.Lengthとはできないということです。
非共有メンバを使用するにはクラスのインスタンス経由で呼び出す必要があります。クラスのインスタンスを作成する一番簡単な方法はNewを使うことです。
FileInfoクラスのLengthプロパティは次のようにすると呼び出すことができます。
Dim
oFile As
New IO.FileInfo("C:\boot.ini") MsgBox(oFile.Length()) |
■リスト5:ファイルのサイズを表示する
どのメンバがが共有メンバで、どのメンバが非共有メンバなのか初めのうちは戸惑うでしょうが、一般的には「その場で単純に情報を与えれば動作可能」なメンバが共有メンバになります。
たとえば、上記のFileInfoクラスのLengthプロパティはファイルのサイズを取得しますが、「どのファイル」のサイズを取得するのかの情報が必要なはずです。ところがLengthプロパティにはその情報を指定する方法が用意されていません。つまり「その場で単純に情報を与える」ことができないメンバなのです。だから非共有メンバです。
他にはFileクラスのCopyメソッドはファイルをコピーするメソッドですが、コピー元ファイル名とコピー先のファイル名の情報が必要ははずです。そしてCopyメソッドはこの情報を引数に指定することができるので、「その場で単純に情報を与えれば動作可能」です。だから共有メンバです。
このような分け方は私は基本的なものだと考えますが、逆説的なきらいがあります。結局のところクラスを作った人がどのような「物」を頭の中で創造したかが反映されているだけです。Lengthプロパティだって引数でファイル名を指定できるようにすることは可能だったはずです。FileInfoクラスを設計した人がそのような使い方を否定しただけです。
なお、実際に使用する場合は . (ドット)書いたときに表示されるメンバの一覧を参考にするとよいでしょう。この一覧にはその場面で使用できるメンバしか表示されません。たとえば、クラス名. と書いた場合には共有メンバの一覧しか表示されません。駅の券売機が投入金額で足りる切符のボタンだけランプが付くのと同じです。使えないものは表示されません。
ただし、表示されていなくても使えるメンバが存在する可能性はあります。
クラスとインスタントと共有メンバと非共有メンバの関係を図にまとめておきます。
■画像2:クラスとインスタントと共有メンバと非共有メンバ
この図を専門用語を使って次のように表現することができます。「コンストラクタ」という言葉についてはすぐ後で説明します。
「このプログラムではNewを使ってPenクラスをインスタンシングします。変数RedPenはPenクラスのインスタンスとなります。コンストラクタの引数にはペンの色を指定しています。」
最後にクラスのインスタンスの作成方法についてまとめておきます。既に何度もでてきていますがインスタンスを作成する一番簡単な方法はNewを使うことですが、これ以外にもインスタンスを取得する方法はありますし、そもそもインスタンシングできないクラスもあります。インスタンスを取得する方法を以下で1つずつ説明してみます。
Newを使ってFileInfoクラスをインスタンシングする例は次の通りです。
Dim oFile As New IO.FileInfo("C:\boot.ini") |
■リスト6:FileIfnoクラスをインスタンシングする例
ちょっとだけ注意して欲しいのは括弧(かっこ)の中です。この例のようにNewを使ってクラスをインスタンシングする場合、括弧の中に必要な情報を指定する必要がある場合があります。これはクラスによって異なります。これはあたかもクラスのインスタンスを返す関数のように動作していることがわかるでしょうか?
このようにクラスをインスタンシングするときに指定する関数のようなものをコンストラクタといいます。今、あやふやに「関数のようなもの」と表現しましたが、実際のところちょっと特殊な関数の一種です。ヘルプ等でインスタンシングの仕方を調べるときはこのコンストラクタの項目を調べてみてください。
リスト6の例は次のリスト7の例の省略形です。
Dim oFile As IO.FileInfo = New IO.FileInfo("C:\boot.ini") |
■リスト7:FileIfnoクラスをインスタンシングする例
宣言とNewは次のように分けて書くこともできます。
Dim
oFile As IO.FileInfo oFile = New IO.FileInfo("C:\boot.ini") |
■リスト8:変数の宣言とインスタンシングを別々に書く例
他のクラスのプロパティやメソッドの戻り値としてクラスのインスタンスが返ってくる場合があります。たとえば、フォームのCreateGraphicsメソッドはGraphicsクラスのインスタンスを返します。
Dim g As Graphics = Me.CreateGraphics |
■リスト9:プロパティからインスタンスを取得する例
このような例はたくさんあります。次の例ではPensクラスののBlueプロパティを使って新しい青いペンのインスタンスを取得することができます。
Dim p As Pen = Pens.Blue |
■リスト10:プロパティからインスタンスを取得する例
PensクラスのBlueプロパティは共有メンバなのでPensクラス自体をインスタンシングする必要はありません。
これらの場合でも、宣言とインスタンスの取得は別々に書くことができます。
Dim
p As Pen p = Pens.Blue() |
■リスト11:宣言とインスタンスの取得を別々に書く例
イベントプロシージャの第1引数と第2引数はクラスのインスタンスです。他にも引数としてインスタンスが渡されてくるプロシージャや関数はおおいにありえます。
次の例は、フォーム上でマウスが移動すると自動的にマウスの位置に赤い円を書きます。その結果、フォーム上にはマウスの軌跡にそうように赤い線ができます。視覚的にちょっと楽しいのでためしに動かしてみてください。
この例の詳しい説明は次回行います。
Private
Sub Form1_MouseMove(ByVal
sender As Object,
ByVal e As
System.Windows.Forms.MouseEventArgs) Handles
MyBase.MouseMove Dim g As Graphics = sender.CreateGraphics() g.FillEllipse(Brushes.Red, e.X, e.Y, 10, 10) End Sub |
■リスト12:マウスの軌跡に沿って赤い円を書く
この例の詳しい意味が分からなくても、どこでインスタンスが使用されているかはわかるなれば心強いです。
この例では、まず、sender(読み方:sender = センダー)が引数として渡されてきたForm1クラスのインスタンスです。そして、そのメソッドCreateGraphics()を使用してGraphicsクラスのインスタンスを取得します。次に円を描くFillEllipseメソッドで使われているのが、引数e(読み方:e = イー)です。この引数もMouseEventArgsクラス(読み方MouseEventArgs = マウスイベントオーグス)のインスタンスです。他にもBrushesクラスのRedプロパティでBrushクラスのインスタンスを作成しています。
BrushesクラスのRedプロパティは共有メンバなのでBrushesクラス自体はインスタンシングする必要がありません。
…ちょっと複雑でしだったかもしれませんね。でもVBのプログラムはこの例のようにクラスだらけなので、こういったことをしっかり理解しておかないと一定以上のレベルには到達できません。初級講座ではまだ理解できていなくても読み進めるようにするつもりですのでここではっきりしたことがわからなくてもめげずに講座を進めていただけると幸いです。