|
Subject:
|
Passing a class by reference
|
|
Posted By:
|
James Diamond
|
Post Date:
|
2/10/2004 7:29:40 AM
|
Hi,
How do I pass an instance of a class to another class?
The reason I need to do this is that I am programming an ActiveX DLL for use in a spreadsheet. The main class (class A in the following example) is instantiated by a call from the spreadsheet. The main class contains another class (class B in the following example).
Therefore, within my VB code, I do not have a handle on the instance of class A. This is a problem, because class B needs to communicate with class A. So - I am trying to pass the class A instance by reference when I instantiate class B. Actually, what I need is (in effect) a pointer (within classB) that points to classA.
In effect...
In classA: ----------
Private B as classB
Public Sub init()
Set B = New classB
Call B.init(Me)
End Sub
In classB: ----------
Private parentClass as classA
Public Sub init(ByRef pc As classA)
parentClass = pc
End Sub
However, the above does not work - it throws an error.
Is my approach all wrong? Or - can I make a slight adjustment to make this work OK?
Hope you can help.
Thanks.
James
//##
|
|
Reply By:
|
jlick
|
Reply Date:
|
2/10/2004 10:46:38 AM
|
This looks fine to me. It would help to know what the error is, and when it occurs.
I am assuming that classA & classB are both in the same DLL. This is important, because you don't want circular references between DLLs.
John R Lick JohnRLick@hotmail.com
|
|
Reply By:
|
gbianchi
|
Reply Date:
|
2/10/2004 10:52:25 AM
|
hi there..
you miss a set in
SET parentclass = pc
that should work..
HTH...
Gonzalo Bianchi
|
|
Reply By:
|
ChrisScott
|
Reply Date:
|
2/10/2004 10:54:05 AM
|
Hi James,
I think this line...
parentClass = pc
Should be...
Set parentClass = pc
HTH,
Chris
|
|
Reply By:
|
James Diamond
|
Reply Date:
|
2/10/2004 11:05:40 AM
|
Lovely boys! Thanks!
"Set" has solved it!
Sorry for the basic error... I am a bit new to VB.
Many many thanks for helping.
James
P.S. Another basic question: Am I right in thinking that parentClass is now effectively a "pointer" to the instance of Class A? That is, if I now change the values of variables in the instance of Class A, then parentClass can be used by the instance of Class B to access those new values?
|
|
Reply By:
|
gbianchi
|
Reply Date:
|
2/10/2004 11:12:20 AM
|
yes.. you are rigth..
but be carefull about circular references...
you have rigth now two pointers two A.. so if you set the main one to nothing..
A will not unload, and b will be alive too, and you cannot reach any of them..
to unload a first you have to set to nothing the A inside B..
the kill B.. and then you can kill A
HTH...
Gonzalo Bianchi
|
|
Reply By:
|
James Diamond
|
Reply Date:
|
2/10/2004 11:33:28 AM
|
Hmmmm....ok
But parentClass is not a COPY of the instance, is it? It's just a pointer to the instance, right?
If I set the instance of classA to nothing ("destroy" it), then parentClass becomes just a pointer to nothing.
Is that right?
|
|
Reply By:
|
gbianchi
|
Reply Date:
|
2/10/2004 12:51:17 PM
|
well.. unless I made a mistake (somebody correct me if i am) destroying an instance of a pointer dont destroy the class, because it have another pointer to it..
try this.. put a msgbox in the terminate of the class..
destroy the first pointer.. and you will see that the msgbox doesnt appear.. so the class is still alive, but you dont have any pointer to it... :(
HTH...
Gonzalo Bianchi
|
|
Reply By:
|
marcostraf
|
Reply Date:
|
2/10/2004 3:43:14 PM
|
No, setting a VB object (or class) to Nothing just decreases the reference count of that object, and the object is destroyed only when the reference count goes to zero. In your case, when you pass your class with the Set statement, the reference count was increased by one. This is the beauty of COM (any VB object is in reality a COM object): classes are destroyed only when no one is use them anymore, so you do not have to worry cleaning up the memory and no need for garbage collector.
But is has a caveat: when you create a circular reference (class A create class B and keeps a pointer to B, and class B keeps a pointer to A) set class A to nothing DOES NOT destroy it, because another class (in this case B) is still using it.
The best way to fix circular references: do not use them.... been there, done it. BTW the garbage collector has been reinstated in .NET
Marco
quote: Originally posted by James Diamond
Hmmmm....ok
But parentClass is not a COPY of the instance, is it? It's just a pointer to the instance, right?
If I set the instance of classA to nothing ("destroy" it), then parentClass becomes just a pointer to nothing.
Is that right?
|
|
Reply By:
|
James Diamond
|
Reply Date:
|
2/11/2004 11:46:14 AM
|
OK - thanks.
It seems to me that I can't avoid this circular reference in this case. I don't know how else to give class B a means of talking to class A. That is because class A is instantiated by a call from my spreadsheet. (class A and class B are in the DLL I am writing in VB6, that is used by the spreadsheet).
If there is another way, please let me know.
A related question... My spreadsheet does this when a command button is clicked:
Set theEngine = New classEngine
The instance of classEngine then does some stuff (including creating some instances of other classes it contains). It then passes results back to the spreadsheet.
When the command button is clicked again, this is repeated. So I would end up with loads of class instances created after many clicks of the button.
I guess this is not very good, as it means loads of redundant objects floating around. Is that right?
Please can you help me understand object-management in this respect, so that I don't go down the wrong route.
Thanks.
James
P.S. Regarding cleanup, when the spreadsheet is closed, am I right in presuming that that destroys all the class instances that I have created via the DLL? i.e. I get an automatic cleanup?
|
|
Reply By:
|
marcostraf
|
Reply Date:
|
2/11/2004 2:35:35 PM
|
James, never create circular references in ActiveX objects. For example:
private syb Button_Click() set theEngine = nwe classEngine .. do something else here end sub
because theEngine is a local variable, VB automatically sets it to nothing before exiting the method, but if you have a circular reference theEngine will be still there eating up memory. In worst cases, even your application will not die hitting the X--the main dialog will close, but the application is still there and you can see in in the task manager.
There are many way to avoid circular reference. In your case I see two easy solutions. First is to declare B withevents, let B sends an event when it changes the variable (passing the variable itself) and class A to catch the event . At the end the two variables in class A and B will be the same. This is coumbersome but it works. I prefer the intermediate class. Create a class C and put the shared variables in it. Declare class C in class A, and pass it to class B via a property: set myClassB.VarC = myClassC in this way both A and B uses the same variable because it is in the same class. This is how I design my components after I learned the problem the hard way. Well, there are ways including creating a 'weak' reference of class A using CopyMemory... I highly discorage the use of it. It is always better to look for 'native' VB solutions.
Marco
|
|
Reply By:
|
James Diamond
|
Reply Date:
|
2/12/2004 12:34:58 PM
|
Marco,
Thanks for your reply, but I am sorry to say that it is rather hard to follow your explanation.
My main problem is that I do not know how a class that I create as a result of a call from my spreadsheet, can be communicated with by other classes in my app (DLL) - because I do not have a handle (name) on that instance of the class.
In my code, the variable "theEngine" is not a local variable to the subroutine. It is a private variable of class B. I am using it to get a way to talk back to the class (theEngine) that created it. But I don't know if this is good practice or not. Can't see how else it could be done.
Still can't see a solution to this. Please can someone help, and shed light on my questions about clean-up etc.?
Thanks.
|
|
Reply By:
|
marcostraf
|
Reply Date:
|
2/12/2004 8:40:45 PM
|
Hi James, thinks get fuzzy here :) let's see if I understood correctly, maybe I am losing it. You created a dll with two classes, a public A and a private B. Your spreadsheet creates an instance of class A, and class A creates an instance of class B, that needs to talk back to A. How am I going so far? Marco
|
|
Reply By:
|
James Diamond
|
Reply Date:
|
2/16/2004 5:07:47 AM
|
Marco,
Yes - that is correct. Thanks for clarifying it. Can you help me find a solution? I have a feeling that if I create a new class C for shared variables, I will still have the same problem.
James
|