1

Quite simple; I've made a class with a method that's public since another class calls this method.

I would like the method only to show up on intellisense in the 2nd class which holds some special reference to the 1st one. Any other class or module should not be able to see the method.

Something along the lines of

Semi-Private (except for Class2) Sub ...

in the method of Class1, or in Class2

Can See Semi-Private methods of Class1
Community
  • 1
  • 1
Greedo
  • 4,967
  • 2
  • 30
  • 78
  • "I've made a class with a method that's public since another class calls this method." - it would be helpful to give the code for this one. – Vityata Jan 10 '18 at 12:01
  • 1
    I usually like the idea of small classes, but it sounds like `Class1` and `Class2` are tightly coupled. Perhaps the methods could be moved into 1 class, then just make the "semi-private" methods `private`. It would improve cohesion. – byxor Jan 10 '18 at 12:02
  • If moving things to 1 class is painful, you should probably leave the methods public. What harm can it cause? – byxor Jan 10 '18 at 12:03
  • The [friend access modifier](http://www.cpearson.com/excel/scope.aspx) limits accessibility to calls from within the same workbook. Not sure if that helps here. – David Rushton Jan 10 '18 at 13:10
  • @destination-data That would only prevent other projects from using the class, and not other modules or classes from using the class. – Brandon Barney Jan 10 '18 at 15:53

3 Answers3

2

Instead of getting complicated with it, and using a roundabout approach, just use the tools meant for the job:

Class Module IFoo

Public Sub Bar()
    ' Interface methods are empty
End Sub

Class Module Foo

Private Type TFoo
    Baz As String
End Type

Private this As TFoo

Implements IFoo

Private Sub Class_Initialize()
    this.Baz = "I am a class that implements IFoo."
End Sub

Private Sub IFoo_Bar()
    ' Do Something
    Debug.Print this.Baz
End Sub

Module Baz

Sub RunBaz()
    Dim MyFoo As IFoo

    ' Note that this WILL NOT work. Nothing happens.
    Set MyFoo = New IFoo
    Debug.Print MyFoo.Bar

    ' Set MyFoo to be equal to a Foo (which implements IFoo)
    Set MyFoo = New Foo
    Debug.Print MyFoo.Baz
End Sub

This makes the methods only visible when the methods are being accessed through an interface which makes them public. Therefore, in order to use the methods in Foo we must first create an instance of Foo using an IFoo variable type.

Then, it is as simple as creating a new class which creates a Foo from an IFoo for its own use.

Class Module IImportantWorker

Public Sub DoSomethingImportant()

End Sub

Class Module ImportantWorker

Private Type TImportantWorker
    Implementation As IFoo
End Type

Private this As TImportantWorker

Implements IImportantWorker

Private Sub Class_Initialize()
    Set this.Implementation = New Foo
End Sub

Public Sub IImportantWorker_DoSomethingImportant()
    this.Implementation.Bar
End Sub

You could get fancy from here and make a property of Foo that is exposed by IFoo that tells it whether or not it can work. This would have to be exposed through the IFoo interface (or, alternatively a separate interface so that the two interfaces must be used in conjunction).

Without locking the class (which I wouldnt recommend anyways, it seems foolish and pointless) Foo will still allow Bar if it is created as a IFoo. But if you just make Foo = New Foo then Foo will do nothing (or rather, expose nothing).

For additional resources, I highly recommend reading these excellent posts that go into greater depth about the processes:

Is VBA an OOP language, and does it support polymorphism?

https://rubberduckvba.wordpress.com/2016/06/16/oop-vba-pt-1-debunking-stuff/

https://rubberduckvba.wordpress.com/2016/07/05/oop-vba-pt-2-factories-and-cheap-hotels/

Brandon Barney
  • 2,382
  • 1
  • 9
  • 18
0

You may create the class that contains all properties and methods, name it BigClass:

Option Explicit

Dim i1 As Integer
Dim i2 As Integer
Dim i3 As Integer


Property Let var1(v As Integer)
    i1 = v
End Property

Property Get var1() As Integer
    var1 = i1
End Property

Property Let var2(v As Integer)
    i2 = v
End Property

Property Get var2() As Integer
    var2 = i2
End Property

Property Let var3(v As Integer)
    i3 = v
End Property

Property Get var3() As Integer
    var3 = i3
End Property

Then you can make classes that inherits BigClass methods, but not necessary all of them. For example, SmallClass1 that will use only var3 variable.

Option Explicit

Dim BigOne As BigClass

Private Sub Class_Initialize()
    Set BigOne = New BigClass
End Sub

Private Sub Class_Terminate()
    Set BigOne = Nothing
End Sub

Property Let var3(v As Integer)
    BigOne.var3 = v
End Property

Property Get var3() As Integer
    var3 = BigOne.var3
End Property

Then you can create SmallClass2 that use var2 and var1 but not var3. You get the point.

Pᴇʜ
  • 56,719
  • 10
  • 49
  • 73
MarcinSzaleniec
  • 2,246
  • 1
  • 7
  • 22
  • But shouldn't you in `SmallClass1` hand `var3` through to the `BigOne` like let `BigOne.var3 = v` and get `var3 = BigOne.var3`? Otherwise this makes not much sense or am I completely wrong? – Pᴇʜ Jan 10 '18 at 13:00
  • You are right, just edited my answer. Anyway, my proposal is to have class that contains all properties and function and class that creates object of the first class and use some of the properties and functions. – MarcinSzaleniec Jan 10 '18 at 13:10
  • 1
    I would avoid the word `Inherit` since VBA doesn't support `Inheritance` and your example is instead exposing members through its own methods, but not inheriting the class. The distinction being that if I add `Sub Foo` to `BigClass` I must also add `Sub Foo` to `SmallClass`. – Brandon Barney Jan 10 '18 at 15:50
0

An clear example would be involved and lengthy and I have deposited one on my blog here VBA - Difference between Friend and Public with inter project references.

Essentially you use the Friend keyword but nothing happens until you split your code across workbooks which itself brings issues such as Instancing and factory functions. Example given should work though. Enjoy!

S Meaden
  • 8,050
  • 3
  • 34
  • 65