Solved Get A Pointer In SubForm To Already Instantiated Class (1 Viewer)

dalski

Member
Local time
Today, 13:05
Joined
Jan 5, 2025
Messages
149
Class-A instantiates Class-B. I need a subform (outside of Class-A & Class-B) to gain access to the instance of Class-B. How do I get a pointer to the instance of Class-B? I could create an object variable of Class-B inside the subform but this would create a new instance of Class-B (undesired). I want to reference the existing Class-B object.

I have declared the Class-B object variable as public & would've thought I could gain access now but this has not worked.
 
Last edited:
Class-B object variable as public & would've thought I could gain access now but this has not worked
If your variable is public in a standard module then yes you should be able to reference directly

If your variable is public in a forms module then think of it as a property of the form. The subform needs to reference it through the form that instantiated it. Something like
Dim bb as clsB
set bb = forms("someform").SomeBvariable

If Class A instantiates an instance of Class B and holds the class variable then you have to go through Class A. Unless again it is intantiating a public variable in a standard module. Which seems like a bad design.
 
Thanks @MajP, understood.
Which seems like a bad design.
That's worrying, hopefully this will change your opinion. Class-A & Class-B's methods & properties are accessed elsewhere. They decouple the current subforms & allow these methods... to be used for other purposes elsewhere in different instantiations of different classes.
I could put all these inside the subform, but then I would need to create another class/ module to contain these identical methods. I thought I was being good by decoupling these methods to be used elsewhere. I agree that it's not nice having the subform in title being tightly coupled with this particular instance of Class-A but i can't see a way around this. I'll be sure to terminate the circular reference. They are in essence tightly coupled & Class-A drives Class-B & the subform. The methods have been decoupled, BUT Class-B allows me to use these beautifully encapsulated methods... elsewhere in many different areas. Possibly a beautiful design :ROFLMAO:?
 
Last edited:
It's not crystal clear to me if you want to have only 1 instance ever of ClassA and ClassB.
If so, then you can use a Static class, like clsErrorHandler in Northwind 2 Developer Edition template.
 
Thanks Tom, there will be multiple instances of Class-A & B later, was unaware of static class so thanks for future.

I failed to mention that Class-A was in a different subform (call it subform-A) when it instantiated the public Class-B object variable. So it seems that because subform-A has lost focus it no longer contains the publicly module level which I was completely unaware of & failed to mention this essential info in the OP (sorry).
I think I'm best to create an instance of Class-B in subform-X to gain access to use it's methods...
 
Thanks Tom, there will be multiple instances of Class-A & B later, was unaware of static class so thanks for future.

I failed to mention that Class-A was in a different subform (call it subform-A) when it instantiated the public Class-B object variable. So it seems that because subform-A has lost focus it no longer contains the publicly module level which I was completely unaware of & failed to mention this essential info in the OP (sorry).
I think I'm best to create an instance of Class-B in subform-X to gain access to use it's methods...

Are both the sub-form-A with instance of Class-B and sub-form-B inside the same main form?

If yes, add a public property to the main form that returns the reference to Class-B in sub-form-A. Then in sub-form-B use that property.

sub-form-B

Set InstanceVar = me.Parent.Form.TheProperty
 
Are both the sub-form-A with instance of Class-B and sub-form-B inside the same main form?

If yes, add a public property to the main form that returns the reference to Class-B in sub-form-A. Then in sub-form-B use that property.

sub-form-B

Set InstanceVar = me.Parent.Form.TheProperty
Would you agree that with the several explanations and amendments, it's about time for a very simple repro database? Might take you less time and would be much more fun for us.
 
was unaware of static class so thanks for future
To be clear there is no such thing as a static class in VBA. When they say that clsErrorHandler in Northwind is static class that is incorrect and misleading. Personally I think they should change the verbiage to a "Pseudo Static Class".
In Northwind 2 it states
This is a static class, meaning the developer does not need to instantiate it, it is always there.
' To use it in your own projects you have to use this procedure: Export File out of this database, and Import File into your database.
' A simple copy/paste of the code is NOT enough.
That is incorrect. It is a predeclared instance of the class. IMO they should explain what is going on and how to create a predeclared class. They provide a link but it is only a definition of the attribute not how to do it. If the purpose of Northwind is to teach they dropped the ball here.

See here for a better discussion of how to make a predeclared class.
.
Chatty explains the difference better between a static class and a predeclared class in vba.
A predeclared class in VBA and a static class (as found in languages like C#) are not the same concept, although they share some functional similarities in how they can be accessed.

Predeclared Class in VBA:
  • In VBA, a class module can be set with the VB_PredeclaredID attribute set to True. This creates a default instance of the class that is automatically available and can be accessed directly using the class name, without needing to explicitly declare and create an object variable using New.
  • This behavior is similar to how Form modules work in VBA, where you can refer to Form1.TextBox1.Text directly without explicitly creating an instance of Form1.
  • While it provides a readily available instance, it's still an instance of the class, meaning it can hold state and you can create additional instances of the same class if needed.
Static Class (in other languages like C#):
  • A static class, in languages that support it, is a class that cannot be instantiated. You cannot create objects of a static class using the new operator.
  • All members (methods, properties, fields) within a static class must also be static.
  • Static classes are typically used for utility functions or collections of related methods that do not require an object instance to operate and often do not maintain state specific to an instance.
Key Differences:
  • Instantiation:
    A predeclared class in VBA can be instantiated (you can create new instances), even though a default one is provided. A static class cannot be instantiated.
  • State:
    A predeclared class's default instance can hold state specific to that instance, and other instances can have their own state. A static class, by design, typically does not hold instance-specific state.
  • Purpose:
    Predeclared classes in VBA are primarily a convenience for accessing a single, default instance easily. Static classes are a design pattern for groups of related functionality that don't require object instantiation.
In summary, while both allow direct access without explicit object creation, a predeclared class in VBA provides a readily available instance of a class, whereas a static class represents a type that cannot be instantiated and contains only static members.
 
Last edited:
You can write a 'provider' class that constructs and exposes other classes.

Imagine you have a cMyClassXProvider which you expose from a standard module as a project-global property like...
Code:
Public Property Get cxp as cMyClassXProvider
    Static prv as New cMyClassXProvider
    set cxp = prv
End Property

...and say cMyClassXProvider exposes methods like...
Code:
Function GetClassA as cClassA
    ' construct and return a valid cClassA instance
    ' maybe each call returns a new instance, or maybe you retain,
    ' and always return, the same one.  Whatever you want.
End Function

Function GetClassB as cClassB
End Function

Function GetClassY(InnerClass As cClassB) as cClassY
    ' returns a cClassY with a cClassB instance inside.
End Function

Now, anywhere in your project, if you type "cxp" and then a period, intellisense pops open with methods GetClassA, GetClassB, and GetClassY ready to insert into your code. An approach like this would make ClassA instances generally available in your project.
 
I assume that ‘static class’ here refers to a class whose ‘VB_PredeclaredId’ attribute is set to ‘True’?

For the sake of simplicity, I always refer to it as a ‘static class’ too.

But technically speaking, it is simply a class of which a default instance exists in VBA, which can be used simply by referring to the class name.

However, you can still create additional instances of such a class.
 
Last edited:
Usually the term Factory is used for such a class.
No, this is more a Service Locator pattern, not a factory. A factory is more under-the-hood, and would not have project-global exposure. The intent of a provider or service locator is to make resources more easily available to other code.
 
Thanks for all contributions. @MarkK I'll look at yours once I get my head around this. I know it's not good design but for now I need to understand scope. Attached is a poor e.g. I know but the goal is to get a deeper understanding of scope & visibility of classes & variables...

1757094970752.png
 

Attachments

Going back to what I said in the first thread.
If class A is the only thing holding a reference to class B you have to access it through Class A.
But since an instance of A is intantiated in a subform you have to reference A through the subform.

I added accessors in class A, but not required. You could have left it public.

Code:
Private m_MB As cB

Public Property Get MB() As cB
    Set MB = m_MB
End Property

Public Property Set MB(ByVal objNewValue As cB)
    Set m_MB = objNewValue
End Property

Subform B can get a reference to you class A instantiated as a property of subform A.
Code:
Private myCB As cB
Private myCA As cA

Private Sub SomeText_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
 
  Set myCA = Me.Parent.Controls("A-Data").Form.mA
  Set myCB = myCA.MB
  MsgBox myCB.ValB
End Sub

You can make this even more unreadable and confusing
Code:
Private Sub SomeText_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
  MsgBox Me.Parent.Controls("A-Data").Form.mA.MB.ValB
End Sub

These names are so undescriptive it will make your head spin.
 
Last edited:
I just doubt this design makes any sense

If you need a single class as a helper that all subforms can use then in standard module you have a global CA and CB. You can use CA as your factory to build CB. You can make these predeclared as people have been describing.

But if you are declaring this in a subform I assume then there is some properties unique to that subform and you would have unique instances per subform.

But I cannot see a scenario where you instantiate a common class in a subform and then have to reference it through the subform. Your classes may make sense, but where and how you are instantiating them does not seem to make sense.
 
Thanks for all contributions. @MarkK I'll look at yours once I get my head around this. I know it's not good design but for now I need to understand scope. Attached is a poor e.g. I know but the goal is to get a deeper understanding of scope & visibility of classes & variables...

View attachment 121425

See my changes

MainForm

Code:
Public Property Get RefClassBFromSubA() As cB
    Dim mA As cA

    Set mA = Me.A_Data.Form.RefA
    Set RefClassBFromSubA = mA.RefB
    
End Property

SubForm-A

Code:
Public Property Get RefA()
    Set RefA = mA
End Property

SubForm-B

Code:
Private Sub SomeText_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
'  MsgBox "How to access cA & cB references?"
  Dim mB As cB
  Dim PF As Form_MainForm
 
  Set PF = Me.Parent.Form
  Set mB = PF.RefClassBFromSubA
  MsgBox "Cb: " & mB.ValB
End Sub

Class cA

Code:
Public Property Get RefB() As cB
    Set RefB = mB
End Property

' Fix
Public Property Get ValA() As Long
'  mValA = ValA
  ValA = mValA
End Property

Class cB

No Change
 

Attachments

MajP
Thankyou
Set myCA = Me.Parent.Controls("A-Data").Form.mA
This is where I was going wrong. I went through the Object Browser more times I could count & I see it now. I fear I'll make this mistake again in the future as I really would have thought it was a more friendly reference by just accessing the subform; & the table/ recordset was out of the equation.
Subform References
Control Object (MSN)
But I cannot see a scenario where you instantiate a common class in a subform and then have to reference it through the subform. Your classes may make sense, but where and how you are instantiating them does not seem to make sense.
I don't disagree, I do not fully understand runtime scope or classes, what is available at what times. This exercise has helped. Thank you for identifying the fault. I think I'll be able to restructure the classes slightly so I don't need to use this referencing. But the exercise has not been without benefit; I know have a better understanding of scope thanks to you guys.

RonPaiii
Thankyou
I see, so you put a property in Subform-A with a reference to the object variable of that particular instance of cls-A. In cls-A a property to cls-B as it was instantiated there. Then in the MainForm another property combining both references. Then in Subform-B refere to the MainForm as an object variable & that allows access; delving further by referring to cls-B's property .ValB.

MarkK
Thankyou, hopefully one day I'll be able to understand. Atm I'm just not at that level sadly.
 
Last edited:

Users who are viewing this thread

Back
Top Bottom