アクセシビリティとはメソッド、プロパティ、クラスや構造体などへのアクセス許可の範囲のことを指します。 アクセシビリティの他にも、可視性やスコープと呼ばれることもあります。
クラスのメソッドの呼び出しをクラス内からのみに限定するか、もしくはクラス外からも呼び出せるように公開するか、といったようにアクセス許可の範囲には様々な程度があります。 アクセス修飾子を指定することにより、メンバのアクセシビリティ、すなわちメンバに対するアクセス許可の範囲をどの程度に限定するか・どの範囲まで公開するかを指定することができます。
アクセス修飾子とアクセシビリティ
アクセシビリティを指定するためのものがアクセス修飾子で、Public
やPrivate
などのキーワードがアクセス修飾子にあたります。
例えば次のようなクラスにおいて、Method1
はアクセス修飾子Public
が指定されているためクラス外からも呼び出すことができますが、Method2
はPrivate
であるためクラス外からは呼び出せず、同一クラス内からのみ呼び出せます。
Class Sample
' アクセス修飾子Publicを指定したメソッド
' (このメソッドはSampleクラス外からのアクセスも可能)
Public Sub Method1()
End Sub
' アクセス修飾子Privateを指定したメソッド
' (このメソッドはSampleクラス内からのアクセスのみ可能)
Private Sub Method2()
End Sub
End Class
Public
やPrivate
以外にも、アクセス範囲を限定するための様々なアクセス修飾子があります。 アクセス修飾子の種類とその概要は次のとおりです。
アクセス修飾子 | 適用されるアクセシビリティ | 詳細 |
---|---|---|
Public
|
すべての箇所からのアクセスを許可 | 同じプロジェクト内・他のプロジェクトのすべての箇所からのアクセスが可能とするように公開する |
Friend
|
プロジェクト内からのアクセスのみ許可 | 同じプロジェクト内からのアクセスは可能とするが、他のプロジェクトからのアクセスは不可能とするように公開する (同じプロジェクト内からのアクセスに対しては Public 相当、他のプロジェクトからのアクセスに対してはPrivate 相当となる) |
Protected
|
クラス内、または派生クラスからのアクセスのみ許可 | 同じクラス内、および派生クラスからのアクセスは可能とするが、クラス外および継承関係にないクラスからのアクセスは不可能とするように公開する |
Private Protected
(VB 15.5以降) |
クラス内、またはプロジェクト内の派生クラスからのアクセスのみ許可 | 同じクラス内、および同じプロジェクト内の派生クラスからのアクセスは可能とするが、クラス外および継承関係にないクラスや、他のプロジェクトで派生しているクラスからのアクセスは不可能とする (同じプロジェクト内からのアクセスに対しては Protected 相当、他のプロジェクトからのアクセスに対してはPrivate 相当となる) |
Protected Friend
|
プロジェクト内、クラス内、または派生クラスからのアクセスのみ許可 | 同じクラス内、および派生クラス、同じプロジェクト内からのアクセスは可能とするが、他のプロジェクトおよび他のプロジェクトで宣言される派生クラスからのアクセスは不可能とするように公開する (同じプロジェクト内からのアクセスに対しては Public 相当、他のプロジェクトからのアクセスに対してはProtected 相当となる) |
Private
|
クラス内からのアクセスのみ許可 | 同じクラス内からのアクセスは可能とするが、派生クラスやクラス外からのアクセスは不可能とする (クラス外には一切公開しない) |
Protected
, Protected Friend
, Private Protected
は、継承に関わるアクセス修飾子であるため、クラスのメンバに対してのみ適用可能です。 それ以外のアクセス修飾子は、クラス以外のメンバに対しても適用可能です。 詳しくは§.アクセス修飾子を適用できる対象でも解説します。
アクセス修飾子とアクセス箇所ごとのアクセス可否をマトリクスにすると次のようになります。
アクセス箇所 | アクセス修飾子 | ||||||
---|---|---|---|---|---|---|---|
Public
|
Protected Friend
|
Friend
|
Protected
|
Private Protected
|
Private
|
||
同じクラス内から | ○ | ○ | ○ | ○ | ○ | ○ | |
同じプロジェクト内の | 派生クラスから | ○ | ○ | ○ | ○ | ○ | × |
クラス外から | ○ | ○ | ○ | × | × | × | |
他プロジェクトの | 派生クラスから | ○ | ○ | × | ○ | × | × |
クラス外から | ○ | × | × | × | × | × |
アクセス修飾子にFriend
が設定されているメンバは、同じプロジェクト内(厳密には同じアセンブリ)からのアクセスに対してはPublic
と同様にすべての箇所からアクセスすることができますが、他のプロジェクトからはPrivate
と同様に一切アクセスすることはできません。
Friend
は同じプロジェクト内のみ可、Protected
は派生クラスのみ可となることを踏まえた上で、Protected Friend
は「Friend
またはProtected
の意」つまり「同じプロジェクト内または派生クラスからであれば可」、Private Protected
は「Friend
かつProtected
の意」つまり「同じプロジェクト内かつ派生クラスからのみ可」と捉えると、アクセス可否の範囲がわかりやすくなります。
アクセス修飾子の選択例としてクラスライブラリを作成する場合を考えると、クラスライブラリ内からのアクセスは許可したいが、クラスライブラリの利用者にはアクセスを許可しないメソッドを作りたい、といった場面ではアクセス修飾子Friend
(およびProtected Friend
)を使うことができます。 Private Protected
も同様で、クラスライブラリ内での派生クラスからはアクセスを許可したいが、クラスライブラリの利用者には許可しない、といった場面に用いることができます。
具体例については後述するFriendとProtected Friendの例、型をPrivate・Protectedにする例もあわせてご覧ください。
アクセス修飾子を適用できる対象
アクセス修飾子は、クラスやメソッドだけでなくメンバ変数やプロパティ、構造体などにも指定することができます。 ただし、すべてのアクセス修飾子をすべての要素に指定できるわけではなく、対象によっては指定できないアクセス修飾子もあります。
次の表は、各アクセス修飾子とそのアクセス範囲、アクセス修飾子を適用できる要素をまとめたものです。
アクセス修飾子 | 適用できる対象 | ||||||
---|---|---|---|---|---|---|---|
クラス | 構造体 | モジュール | クラスメンバ | 構造体メンバ | モジュールメンバ | ローカル変数 | |
Public
|
○ | ○ | ○ | ○ | ◎ | ○ | |
Friend
|
◎ | ◎ | ◎ | ○ | ○ | ○ | |
Protected
|
○ | ||||||
Private Protected
(VB 15.5以降) |
○ | ||||||
Protected Friend
|
○ | ||||||
Private
|
○ | ○ | ○ | ◎ | ○ | ◎ | |
Dim
|
○ | ○ | ○ | ○ |
表中の◎はアクセス修飾子を指定しなかった場合のデフォルトのアクセシビリティです。 例えば構造体ではメソッドにアクセス修飾子を指定しなかった場合はPublic
として扱われますが、クラスではメソッドにアクセス修飾子を指定しなかった場合はPrivate
として扱われます。
Dimはローカル変数の宣言だけでなくクラス・構造体のメンバ変数を宣言する際にも指定することができます。 Dim自体はアクセス修飾子ではありませんが、Dimを使って宣言されたメンバ変数のアクセシビリティはデフォルトと同じ、つまり構造体ではPublic、クラス・モジュールではPrivateで宣言されているのと同じものとして扱われます。
ローカル変数はメソッド内でのみ有効である(ローカル変数はメソッド外に公開できない)ため、アクセス修飾子を指定することはできません。 (ブロックと変数のスコープ)
アクセス修飾子の適用例
次のサンプルはアクセス修飾子の適用とメンバの公開範囲を例示したものです。 詳細はコメントにあるとおりです。
' このクラスはプロジェクト外にも公開される
Public Class C
' このメソッドはクラス外にも公開される
Public Sub Method1()
End Sub
' このメソッドはクラス内のみに公開される
Private Sub Method2()
End Sub
' このメソッドはクラス内のみに公開される (=Private)
Sub Method3()
End Sub
' このフィールドはクラス外にも公開される
Public Field1 As Integer
' このフィールドはクラス内および派生クラスにのみ公開される
Protected Field2 As Integer
' このフィールドはクラス内にのみ公開される
Private Field3 As Integer
' このフィールドはクラス内にのみ公開される (=Private)
Dim Field4 As Integer
End Class
' この構造体はプロジェクト外には公開されない (=Friend)
Structure S
' このメソッドは構造体外にも公開される
Public Sub Method1()
End Sub
' このメソッドは構造体内にのみ公開される
Private Sub Method2()
End Sub
' このメソッドは構造体外にも公開される (=Public)
Sub Method3()
End Sub
' このフィールドは構造体外にも公開される
Public Field1 As Integer
' このフィールドは構造体内にのみ公開される
Private Field2 As Integer
' このフィールドは構造体外にも公開される (=Public)
Dim Field3 As Integer
End Structure
Class Sample
Shared Sub Main()
Dim c As New C
' クラスCのこれらのメンバにはアクセス可能
c.Method1()
c.Field1 = 16
Dim s As S
' 構造体Sのこれらのメンバにはアクセス可能
s.Method1()
s.Method3()
s.Field1 = 42
s.Field3 = 3
End Sub
End Class
型のアクセシビリティとメンバの公開範囲
メンバの公開範囲は型の公開範囲より広くすることはできません。 例えば、Friendアクセス修飾子が指定されているモジュールの場合、このモジュールはプロジェクト内からしかアクセスできません。 このモジュール内でPublic修飾子を指定したメソッドを宣言したとしても、そのメソッドはモジュール自体と同じくプロジェクト内からしかアクセスできません。
' このモジュールはプロジェクト外にも公開される
Public Module M1
' このメソッドはプロジェクト外からも呼び出すことができる
Public Sub Method1()
End Sub
End Module
' このモジュールはプロジェクト外には公開されない
Friend Module M2
' このメソッドはプロジェクト外から呼び出すことはできない
Public Sub Method1()
End Sub
' Method1と以下のMethod2は同じアクセシビリティとなる
Friend Sub Method2()
End Sub
End Module
公開範囲についてはネストされた型の場合もあわせてご覧ください。
FriendとProtedted Friend
アクセス修飾子FriendとProtected Friendが指定されたメンバは、同じプロジェクト(アセンブリ)内ではどちらもPublicと同様のアクセシビリティを持ちます。
Public Class C
' このメソッドはプロジェクト内にのみ公開される
Friend Sub M1()
End Sub
' このメソッドはプロジェクト内、および派生クラスにのみ公開される
Protected Friend Sub M2()
End Sub
' このメソッドはプロジェクト外にも公開される
Public Sub M3()
End Sub
End Class
Class X
Sub M()
Dim c As New C
' クラスCのメソッドM1およびM2は、同じプロジェクト内から見れば
' Publicと同様なので呼び出すことができる
c.M1()
c.M2()
' 当然、クラスCのメソッドM3も呼び出すことができる
c.M3()
End Sub
End Class
一方で、別のプロジェクト(アセンブリ)からはアクセス修飾子Friendが指定されたメンバはPrivate、Protected Friendが指定されたメンバはProtectedと同様のアクセシビリティとなります。 上記のプロジェクトProject1で定義されているクラスCを使用する別のプロジェクトProject2では、各メソッドのアクセシビリティは次のようになります。
Class C1
Inherits C ' Project1のクラスCを継承
Sub M()
' Project1で定義されているクラスCのメソッドM1はFriendであり、
' Project2から見るとPrivateなメソッドと同様なので呼び出すことはできない
'M1()
' 一方クラスCのメソッドM2はFriend Protectedで、
' Project2から見るとProtectedなメソッドと同様なので呼び出すことができる
M2()
' 当然、クラスCのメソッドM3はPublicであるため呼び出すことができる
M3()
End Sub
End Class
Class Y
Sub M()
' Project1で定義されているクラスCはPublicなのでインスタンスを
' 作成することができる
Dim c As New C
' クラスCのメソッドM1、M2はPublicではないので別のプロジェクトから
' 呼び出すことはできない
'c.M1()
'c.M2()
' 一方クラスCのメソッドM3はPublicであるため呼び出すことができる
c.M3()
End Sub
End Class
プロパティとアクセシビリティ
プロパティでは、SetプロシージャとGetプロシージャで異なるアクセシビリティを設定することができます。 これにより、クラス外からの値の取得は許可するが、値の設定はクラス内のみに限定する、といったプロパティを用意することができます。
Class C
Dim _p As Integer
Property P As Integer
' プロパティPへの値の設定はクラス内および派生クラスからのみに限定する
Protected Set (ByVal val As Integer)
_p = val
End Set
' プロパティPの値の取得はクラス内外両方に許可する
Public Get
Return _p
End Get
End Property
End Class
プロパティ宣言自体にアクセス修飾子を指定した場合は、SetプロシージャとGetプロシージャにそのアクセシビリティが適用されます。 プロパティ宣言自体にアクセス修飾子が指定されていても、SetプロシージャまたはGetプロシージャにアクセス修飾子を指定すれば、そのアクセシビリティが適用されます。
Class C
Dim _p As Integer
' PublicなプロパティPを宣言
Public Property P As Integer
' Privateが指定されているため、プロパティPへの値の設定はクラス内のみで可能となる
Private Set (ByVal val As Integer)
_p = val
End Set
' アクセス修飾子が指定されていないため、プロパティPの値の取得はPublicとなる
Get
Return _p
End Get
End Property
End Class
プロパティ宣言の構文についてはプロパティを参照してください。
ネストされた型とPrivate・Protected
クラス・構造体・モジュール自体にもPrivateアクセス修飾子を指定することはできますが、名前空間直下に属するものにはPrivateを指定することはできません。 Privateが指定できるのはいずれかの型の中で宣言された型、つまりネストされたクラス・構造体・モジュールのみです。 クラスであれば、これらは入れ子クラス・内部クラス・インナークラスなどと呼ばれます。
ネストされた型のメンバを参照できるようにするには、そのメンバにアクセス修飾子PublicもしくはFriendを指定する必要があります。 アクセス修飾子Privateを指定した場合は、ネストされた型の内部のみでしか参照できなくなります。
Class C
' Publicなインナークラス
Public Class CI1
' このメソッドはクラス外に公開される
Public Sub M1()
End Sub
End Class
' Privateなインナークラス
Private Class CI2
' このメソッドはクラスCI2外に公開される
Public Sub M1()
End Sub
' このメソッドはクラスCI2外には公開されない
Private Sub M2()
End Sub
End Class
Sub M()
' インナークラスCI1は同一クラス内で宣言されているのでインスタンスを作成できる
Dim ci1 As New CI1
' インナークラスCI1のメソッドM1はPublicなので呼び出すことができる
ci1.M1()
' インナークラスCI2も同様に同一クラス内で宣言されているのでインスタンスを作成できる
Dim ci2 As New CI2
' インナークラスCI2のメソッドM1はPublicなので呼び出すことができる
ci2.M1()
' 一方メソッドM2はPrivateなので呼び出すことはできない
'ci2.M2()
End Sub
End Class
Class X
Sub M()
' クラスCのインナークラスCI1はPublicなのでインスタンスを
' 作成することができる
Dim ci1 As New C.CI1
' 一方インナークラスCI2はPrivateなのでインスタンスを
' 作成することはできない
'Dim ci2 As New C.CI2
End Sub
End Class
クラスの場合、ネストされた型にアクセス修飾子Protectedを指定することができます。 Protectedが指定された型は、型が宣言されているクラスとその派生クラスにのみ公開されます。
Class C
' Protectedなインナークラス
Protected Class CI
End Class
End Class
Class C1
' クラスCを継承
Inherits C
Sub M()
' インナークラスCIは基底クラスCで宣言されたProtectedなクラスなので
' インスタンスを作成できる
Dim ci As New CI
End Sub
End Class
Class X
Sub M()
' クラスXはクラスCとは継承関係にないため、インナークラスCIの
' インスタンスを作成することはできない
Dim ci As New C.CI
End Sub
End Class
ネストされた型と親クラスのメンバのアクセシビリティ
ネストされた型からは親クラスのすべてのメンバを参照することができます。 例えば、次のようにインナークラスから親クラスのPrivateなメソッドを呼び出すこともできます。
Class C
' Privateなメソッド
Private Sub M()
End Sub
' インナークラス
Private Class CI
Private c As C
' コンストラクタで親クラスのインスタンスを受け取る
Public Sub New(ByVal c As C)
MyClass.c = c
End Sub
Sub M()
' 親クラスCのPrivateなメソッドMを呼び出す
c.M()
End Sub
End Class
End Class
インターフェイスの実装とアクセシビリティ
インターフェイスの実装となるメンバは、そのアクセシビリティと無関係に参照可能となる点に注意が必要です。 次の例のように、インターフェイスのメソッドをPrivateなメソッドとして実装していたとしても、インターフェイス型にキャストすればそのメソッドを呼び出すことが可能となります。
Class C
' IDisposableインターフェイスを実装する
Implements IDisposable
' IDisposable.Disposeの実装となるメソッド
Private Sub Dispose() Implements IDisposable.Dispose
Console.WriteLine("disposed")
End Sub
End Class
Class Sample
Shared Sub Main()
Dim c As New C
' C.DisposeメソッドはPrivateなので直接呼び出すことはできない
'c.Dispose()
' CをIDisposableにキャスト
Dim d As IDisposable = DirectCast(c, IDisposable)
' C.DisposeメソッドがPrivateでも、IDisposableインターフェイスを介して
' Disposeメソッドを呼び出すことができる
d.Dispose()
End Sub
End Class