Accessibility in Class Modules

The notion of accessibility (or scope) in class modules is more involved than it is in standard modules. As far as local variables (block-level and procedure-level) are concerned, there is no difference — we have block scope and procedure-level scope.

However, members of a class module can be assigned one of the following access modifiers:

  • Public

  • Private

  • Friend

  • Protected

  • Protected Friend

(For standard modules, only Public, Private, and Friend are allowed.)

Actually, we can dispense with the Protected Friend modifier in one statement: Protected Friend is equivalent to Protected or Friend. Put another way, if Protected sets a specific range of accessibility (or inheritance — see below) and Friend sets a different range, then Protected Friend sets accessibility to the union of those ranges — if a member falls into either range, it passes the accessibility (or inheritance) criterion.

Note that class modules themselves can be declared with any one of the three access modifiers: Public, Private, or Friend (Protected is not allowed). When a class module declaration specifies one of these access modifiers, this simply restricts all of its members to that level of access, unless a member’s access is further restricted by the access modifier on the member declaration itself. For instance, if the class has Friend access, no member can have Public access. (Put another way, the Public access is overridden by the Friend class access.)

On the other hand, all four access modifiers apply to members of the class module — that is, to variable, constant, enum, and procedure declarations within the class module.

To avoid confusion in discussing the access modifiers, it helps to separate the issue of accessibility of members from that of inheritance of members.

Member Inheritance

Let us first address member inheritance. Suppose that a class named Class1 has a derived class named Class1Derived, as shown in the following:

Public Class Class1
    Public pub As Integer = 1
    Private priv As Integer = 1
    Protected p As Integer = 1
    Friend f As Integer = 1
    Protected Friend pf As Integer = 1
End Class

Public Class Class1Derived
    Inherits Class1
    Public Sub test(  )

        ' Not allowed - private members are not inherited
        Me.priv = 4   

        ' Allowed only in derived classes in the same project as base class
        Me.f = 4

        ' Allowed in all derived classes
        Me.pub = 4
        Me.p = 4
        Me.fp = 4

    End Sub
End Class

Note that the Me. syntax is optional, and we could write, for instance, simply:

pub = 4
p = 4
f = 4
fp = 4

The fact that the code:

Me.p = 4

is valid in Class1Derived means that this class has inherited the member p. In other words, an object of class Class1Derived has a member variable named p. The fact that:

Me.f

fails to work in Class1Derived if Class1Derived is in a different project than Class1 means that such classes do not inherit the member f.

Now, the rules of inheritance are:

  • Private members are never inherited.

  • Public members are inherited by all derived classes.

  • Protected members are inherited by all derived classes (and therefore so are Protected Friend members).

  • Friend members are inherited by all derived classes in the same project as the base class only.

Member Accessibility

Now we come to member accessibility. Unfortunately, the term accessibility is used quite loosely in most documentation, but to make absolutely clear sense of the issue, we must be specific. Many writers simply refer to a member’s accessibility, but this is ambiguous. To illustrate, consider the code:

Public Class Class1
    Public x As Integer = 1
End Class

Public Class Class2
    Inherits Class1
End Class

Now, it makes sense to ask about the accessibility of the Public member x of Class1 or the (inherited) Public member x of Class2. It does not make sense to ask about the accessibility of the member x alone, without mention of the class involved. Indeed, we say that the Public member x of Class1 is accessible from a class Class3 if the following is legal:

Public Class Class3
   Public Sub Test(  )
      Dim c1 As new Class1(  )
      c1.x = 5
   End Sub
End Class

On the other hand, the Public member x of class Class2 is accessible from Class3 if we can write:

Public Class Class3
   Public Sub Test(  )
      Dim c2 As new Class2(  )
      c2.x = 5
   End Sub
End Class

With this in mind, we can describe the accessibility rules clearly:

Private

If ClassA is a class with a Private member m, we cannot access the member m of ClassA from any other class.

Public

If ClassA is a class with a Public member m, we can access the member m of ClassA from any other class.

Friend

If ClassA is a class with a Friend member m, we can access the member m of ClassA from any other class that is in the same project as ClassA.

Protected

Let m be a Protected member of ClassA. Then from any subclass ClassB of ClassA, we can access the member m of ClassB or the member m of any subclass of ClassB. Another way to phrase this is as follows. Let m be declared as Protected in a class ClassA. Let Class B be a subclass of ClassA. Then the member m of ClassB is accessible in each class between ClassB and ClassA in the inheritance hierarchy.

Clearly, the definition of Protected needs clarification. To do so, consider a chain of derived classes (that is, ClassN+1 is derived from ClassN):

Class1
Class2
.
.
.
ClassA
   ' This is the first appearance of the protected method MyMethod
   ' Thus, all classes below inherit MyMethod
   Protected Sub MyMethod(  )
.
.
.
ClassB
   ' ClassB can call MyMethod because it has been inherited
   ' This is accessibility of MyMethod for ClassB
   MyMethod(  )
   ' Note that this is equivalent to 
   Me.MyMethod(  )
   ' Can access MyMethod for any Class at or below this class
   ' For example, the following are legal:
   Dim b As New ClassB
   b.MyMethod(  )
   Dim c As New ClassC
   c.MyMethod(  )
   ' But the following is not legal
   Dim a As New ClassA
   a.MyMethod(  )
.
.
.
ClassC
   ' Can access MyMethod for any Class at or below this class
   ' For example, the following are legal:
   Me.MyMethod(  )
   Dim c As New ClassC
   c.MyMethod(  )
   Dim d As New ClassD
   d.MyMethod(  )
   ' But the following is not legal
   Dim b As New ClassB
   b.MyMethod(  )
.
.
.
ClassD
.
.
.
ClassN

As you can see, the rules for Protected mode access are a bit involved. Actually, Protected mode should be used with some care. For instance, declaring a member variable Protected violates one of the principal rules of good object-oriented programming, encapsulation, as does declaring the member Public. Thus, it should be done only if you are certain that derived classes will be well behaved (or are willing to accept the risk). The same applies to Protected methods.

Get VB.NET Language in a Nutshell, Second Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.