关于set语句的疑惑

无·法 2009-09-18 04:13:22
Class1这个类只有一个公有成员i
Dim c1 As New Class1
Dim c2 As Object

Set c2 = c1'c2指向c1,作为引用,并不创建一个实例

c1.i = 1
MsgBox c1.i'1
MsgBox c2.i'1

c2.i = 8
MsgBox c1.i'8
MsgBox c2.i'8

Set c1 = Nothing'这个时候c2是不是自动创建了一个实例?下面代码好像可以证明
MsgBox c1.i'0

c1.i = 2'我一直以为set为nothing后就不可以使用了的呢,这里可以照样用,只是结果都是初始的了
MsgBox c1.i'2
MsgBox c2.i'8,这里的值出现了差异

c2.i = 9
MsgBox c1.i'2
MsgBox c2.i'9,这里同上
...全文
129 21 打赏 收藏 转发到动态 举报
写回复
用AI写文章
21 条回复
切换为时间正序
请发表友善的回复…
发表回复
无·法 2009-09-19
  • 打赏
  • 举报
回复
西西,你讲得太详细了,非常适合做讲师,再次感谢
slowgrace 2009-09-19
  • 打赏
  • 举报
回复
呵呵。想起我手头有中文的程序员指南,摘给你对应的文字看看:

对象引用和引用计数
对象存活期的基本规则是非常简单的:当对某个对象的最后引用被释放时,该对象就被撤销。不过,伴随如此长的存活期,简单并不总意味着容易。

随着使用更多对象,并保存了更多包含对那些对象引用的变量的时候,那么,可能要经历这样一些时期,那时,要撤销自己的对象,而且觉得应能撤销时,实际上却又不可能撤销。

在某个点上,应当能想到,Visual Basic 必须记录对象引用——否则它怎么能知道对象的最后引用何时释放呢?可能开始意识到了:如果只有自己能对 Visual Basic 的引用计数进行访问,那么调试将变得非常容易。

不幸的是,事实并非如此。为了更有效地使用对象,部件对象模型 (COM) 对其引用计数的规则指定了许多复杂的快捷方式。所造成的后果是让人不能信赖引用计数的值——即使已经得到了它。

根据 COM 规则,可以信赖的信息仅为,引用值是否为 0。可以知道什么时候该引用值到达 0,因为对象的 Terminate 事件出现了。除了那个以外,从引用计数中就再也搜集不到任何可靠的信息了。

……
提示:不要将变量声明为 As New。它们就像吹灭后会重新点燃的生日蜡烛一样:
如果在将它设置为 Nothing 后又使用,那么 Visual Basic 会强制性地创建另一个对象。
liguicd 2009-09-18
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 slowgrace 的回复:]
在这一节的底部有这样一段:

Don't declare variables As New. They're like those birthday candles that re-ignite after you blow them out:If you use one after you've set it to Nothing, Visual Basic obligingly creates another object.
[/Quote]
用Google翻译后...
不要声明为新变量。他们喜欢那些生日蜡烛,重新点燃后,你吹出来:如果您使用一个在您设定为Nothing,乖乖Visual Basic中创建另一个对象。
slowgrace 2009-09-18
  • 打赏
  • 举报
回复
在这一节的底部有这样一段:

Don't declare variables As New. They're like those birthday candles that re-ignite after you blow them out: If you use one after you've set it to Nothing, Visual Basic obligingly creates another object.
slowgrace 2009-09-18
  • 打赏
  • 举报
回复
mk:@MSITStore:C:\Program%20Files\Microsoft%20Visual%20Studio\MSDN\2001OCT\1033\vbcon98.chm::/Html/vbconobjectreferencesreferencecounting.htm

MSDN里有一节,标题叫:Object References and Reference Counting

摘一段给你:

The primary rule for object lifetime is very simple: An object is destroyed when the last reference to it is released. However, as with so much of life, simple doesn't always mean easy.

As you use more objects, and keep more variables containing references to those objects, you may go through periods when it seems impossible to get your objects to go away when you want them to.

At some point, it will occur to you that Visual Basic must be keeping track of object references — otherwise how could it know when the last reference to an object is released? You may start thinking that if only you could get access to Visual Basic's reference counts, debugging would be much easier.

Unfortunately, that's not true. To make using objects more efficient, the Component Object Model (COM) specifies a number of complex shortcuts to its reference counting rules. The net result is that you couldn't trust the value of the reference count even if you had access to it.

According to COM rules, the only information you can depend on is whether or not the reference count is zero. You know when the reference count reaches zero, because your object's Terminate event occurs. Beyond that, there's no reliable information to be gleaned from reference counts.
无·法 2009-09-18
  • 打赏
  • 举报
回复
谢谢西西的鼎力相助!也也谢谢其他朋友!
不过这个关于引用的计数器的概念在学Delphi时听说过,这里也有?西西你这个概念是从哪里来的呢?不过目前来看你这个解释最合理了,也就是说这个实例是实实在在存在于内存中,谁都可以引用,并不是谁独享的。
slowgrace 2009-09-18
  • 打赏
  • 举报
回复
0楼代码的注释如下:

Sub Test_Cls()
Dim c1 As New Class1
Dim c2 As Object

Set c2 = c1
'由于c1以New声明,这个语句实际上发生了如下动作:'
'(1)生成一个Class1对象,不妨称为对象D'
'(2)把c1指向对象D,对象D的引用计数变为1'
'(3)把c2指向对象D,对象D的引用计数变为2'

'现在无论是操作c1还是c2,实际上都是在操作对象D'
c1.i = 1
Debug.Print c1.i '1
Debug.Print c2.i '1

c2.i = 8
Debug.Print c1.i '8
Debug.Print c2.i '8

Set c1 = Nothing
'释放c1对对象D的引用,对象D的引用计数变为1'
'对象指针c1现在指向nothing'

Debug.Print c1.i '0
'由于c1以New声明,所以上述语句做了如下事情:'
'(1)生成一个新的Class1对象,不妨称为对象E'
'(2)把c1指向对象E,对象E的引用计数变为1'

c1.i = 2 '设置对象E的成员变量i为2'
Debug.Print c1.i '2 c1指向对象E
Debug.Print c2.i '8 c2指向对象D

c2.i = 9 '设置对象D的成员变量i为9'
Debug.Print c1.i '2 对象E
Debug.Print c2.i '9 对象D
End Sub
slowgrace 2009-09-18
  • 打赏
  • 举报
回复
3楼代码的注释如下:

Option Explicit

Dim c2 As Object

Private Sub Command1_Click()
MsgBox c2.i '9
End Sub

Private Sub Form_Load()
Dim c1 As New Class1
c1.i = 9
'生成一个新的Class1对象(不妨称为对象C),并将c1指向它'
'对象C的引用计数加1,其引用计数为1'

Set c2 = c1
'将c2也指向对象C'
'对象C的引用计数加1,其引用计数现在为2'

'过程结束,局部变量c1被释放'
'c1所指向的对象C的引用计数相应的减1,变为1'
'c2是模块级变量,不会被释放'
'对象C的引用计数不为0,不会被销毁'
'所以在过程结束后仍然可以被访问到'
End Sub
贝隆 2009-09-18
  • 打赏
  • 举报
回复
这好比C语言中的指针,有两个变量指向了同一内存地址(C1和C2),你之取消了其中之一,而并没有全部取消,也就是没有卸载变量。
slowgrace 2009-09-18
  • 打赏
  • 举报
回复
Sub test_rst()
Dim rs1 As ADODB.Recordset, rs2 As ADODB.Recordset

Set rs1 = ……
'对应的记录集对象(不妨称为A)的引用计数加1
'假设A原来的计数为0,那么它现在的引用计数为1

Set rs2 = rs1
'对象A的引用计数加1,变为2

Set rs2 = Nothing
'对象A的引用计数减1,变为1

'过程结束,局部变量rs1退出有效范围,它对A的引用被释放'
'A的引用计数再减1,变为0,A被销毁'
End Sub
king06 2009-09-18
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 slowgrace 的回复:]
引用 9 楼 king06 的回复:
Set c1 = Nothing
改为 Set c2 = Nothing试试,相信此时c1也变为nothing了

不对。现在这个对象的引用计数为2,只set nothing一次,引用计数变为1,不为0,对象还是不会被销毁。
[/Quote]
???为啥“引用计数为2”呢
这个具体没去验证,不过我在记录集上用的时候确是如此。。。
dim rs1 as adodb.recordset,rs2 as adodb.recordset
set rs1=……
-------
set rs2=rs1
set rs2 =nothing

slowgrace 2009-09-18
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 king06 的回复:]
Set c1 = Nothing
改为 Set c2 = Nothing试试,相信此时c1也变为nothing了

[/Quote]

不对。现在这个对象的引用计数为2,只set nothing一次,引用计数变为1,不为0,对象还是不会被销毁。
king06 2009-09-18
  • 打赏
  • 举报
回复
Set c1 = Nothing
改为 Set c2 = Nothing试试,相信此时c1也变为nothing了
slowgrace 2009-09-18
  • 打赏
  • 举报
回复
你在3楼的代码,c1是局部变量,它对应的对象在过程结束后会自动将引用计数减一,但是由于该对象同时被模块级变量c2引用,所以并不会被销毁,所以之后你还是可以看到它。

hanvan 2009-09-18
  • 打赏
  • 举报
回复
有两个变量指向同一个实例的时候,例如c1,c2都指向某一个内存区域。
只有当
set c1 = nothing
set c2 = nothing
时,且没有其他变量指向这一实例时,该实例的内存才被释放。
slowgrace 2009-09-18
  • 打赏
  • 举报
回复
以New声明一个对象变量的话,并不会立即生成新的对象。而只是在你第一次用到它的属性后会自动生成一个新对象。所以你0楼的代码在set c1=Nothing之后,再MsgBox c1.i,会自动生成一个新的class1对象,该对象的i成员缺省为0.
slowgrace 2009-09-18
  • 打赏
  • 举报
回复
以New声明一个对象变量的话,并不会立即生成新的对象。而只是在你第一次用到它的属性后会自动生成一个新对象。所以你0楼的代码在set c1=Nothing之后,再MsgBox c1.i,会自动生成一个新的class1对象,该对象的i成员缺省为0.
slowgrace 2009-09-18
  • 打赏
  • 举报
回复
set nothing只是使相应对象的引用计数减一,只要当对象的引用计数减为0后对象才会真的被销毁。
无·法 2009-09-18
  • 打赏
  • 举报
回复
下面的代码将c1最为一个局部变量了,这样c1总该释放了吧?因为都不存在了,c2到底自己有没有个实例,是不是在引用消失了后自动的拷贝过来?
Option Explicit

Dim c2 As Object

Private Sub Command1_Click()
MsgBox c2.i'9
End Sub

Private Sub Form_Load()
Dim c1 As New Class1
c1.i = 9
Set c2 = c1
End Sub
无·法 2009-09-18
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 hanvan 的回复:]
有什么问题?这很正常啊。
当 set c1 = nothing 时,释放了c1的指向。但是因为还有c2引用实例,故实例并没有被释放。
c2根本没有被取消指向过。
[/Quote]
你这里是释放是什么意思?按你说的下面的代码应该是释放了?
Dim c1 As New Class1
c1.i=8
Set c1 = Nothing
MsgBox c1.i'0

难道释放就是指数据都初始化?
加载更多回复(1)

7,762

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧