Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/vba/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Class 在for()循环中声明和初始化的VBA对象的范围_Class_Vba_Scope - Fatal编程技术网

Class 在for()循环中声明和初始化的VBA对象的范围

Class 在for()循环中声明和初始化的VBA对象的范围,class,vba,scope,Class,Vba,Scope,我有一个类“Portfolio”(它的字段之一是类“Stock”)方法,代码如下: For i = 1 To n Dim TempStock As New Stock TempStock.Set_Stock 'sets TempStock ... Next i 其中“Stock”是我的用户定义类,具有以下结构、构造函数和析构函数: Private StockName As String Private CurDate As Date Pri

我有一个类“Portfolio”(它的字段之一是类“Stock”)方法,代码如下:

For i = 1 To n
    Dim TempStock As New Stock
    TempStock.Set_Stock            'sets TempStock    
    ...
Next i
其中“Stock”是我的用户定义类,具有以下结构、构造函数和析构函数:

Private StockName As String
Private CurDate As Date
Private BidPrice As Double
Private AskPrice As Double
Private StockDivs As Dictionary

Private Sub Class_Initialize()
    Set StockDivs = New Dictionary
End Sub
Private Sub Class_Terminate()
    Set StockDivs = Nothing
End Sub
我的意思是,在每个循环中,我将声明并初始化带有空字段的新临时对象。但是在一步一步地运行我的程序之后,在我看来类_Terminate()并没有在循环结束时被调用。在下一步中,
TempStock
的所有字段都已设置为上一个循环中的字段。因此,我不理解以下内容:

1) 为什么不在下一个i调用
Class_Terminate()
?什么时候叫?现在写对了吗?或者我也应该编写代码,将每个非对象字段设置为空值

2) 好的,它没有被调用,但我仍然有
Dim TempStock作为新股票
?它不应该给我双重声明错误吗?或者至少将
TempStock
设置为新的空对象

3) 以下两者之间的区别是什么:

 Dim TempStock As New Stock
以及:

这和我的问题有关吗


如果您能帮我解决任何问题,我们将不胜感激,谢谢

VBA中没有块级范围;所有声明(
dim
)都被提升到包含过程的顶部,并且仅在例程结束时超出范围

您是正确的,因为您看到的行为是新的
,当前该类将在循环中实例化一次&直到过程返回时它退出范围后才终止

要获得您想要的行为,您必须使用:

 Dim TempStock As Stock
 Set TempStock = New Stock
因为是
集合
显式地强制将新对象实例分配给
TempStock


当声明被挂起时,
Dim TempStock As New Stock
行实际上不会立即创建
Stock
的新实例,相反,这种对象创建方式会为跨越
Stock
类型变量的每次调用插入存根代码,该变量表示“如果我不是有效引用,请立即自动创建我”.

如果应用语法:

Dim TempStock As Stock
Set TempStock = New Stock
将调用析构函数。
VBA中的对象销毁发生在引用对象的引用计数为零(无)时。
在本例中,在每个循环中,您都使用相同的变量“TempStock”实例化一个全新的“Stock”对象,该对象将导致前一个对象从内存中释放

这段代码是不必要的,因为对象将被销毁:

Private Sub Class_Terminate()
    Set StockDivs = Nothing
End Sub
如果在main sub中将StockDivs显式设置为nothing,则会注意到类_Terminate事件将被调用,因此在这种情况下,对象将在引用计数为零时第二次接收另一个释放消息(否则将不会调用此事件)

关于:

Dim TempStock As New Stock  
根据微软的说法,这两个公式是等价的:

然而,等效并不意味着它们完全相同。
在声明中直接使用New关键字确实也会实例化Stock对象,但是正如您所注意到的,构造函数只被调用一次,析构函数只在循环结束时被调用。这意味着您在每个循环中反复使用同一对象,同时在同一对象上重新分配属性(但实际上没有释放它)。
这个公式的典型特点是,对象上的初始值设定项不是在声明时调用的,而是在首次使用后才调用。
在大多数用例中,两者最终都可以使用相同的结果

我猜你可能有用的是下面的代码。 除非您想将多个股票添加到集合中(您也可以使用字典),否则我看不出在分配属性时多次循环同一类的直接原因

Option Explicit

Sub Stocks()

Dim oCollection         As Collection
Dim TempStock           As Stock
Dim lCnt                As Long


Set oCollection = New Collection

For lCnt = 1 To 5

    Set TempStock = New Stock

    TempStock.Set_Stock ("Stock_" & lCnt)       'sets TempStock name eg. 
    oCollection.Add TempStock
Next lCnt

End Sub

将多个股票添加到集合中

但此时第二个循环中的“旧”TempStock对象会发生什么:Set TempStock=newstock?是否调用了Class_Terminate()?第二次调用
Set TempStock=New Stock
会导致Class_在新实例上初始化,然后在现有实例上终止。Class_Terminate是一个在引用计数达到零时自动调用的事件。由于变量Tempstock在每个循环的堆上都被分配了一个“新”对象,因此前一个对象被释放,并且该(已释放)对象上的析构函数被调用。TempStock被声明为持有一个类对象,因此不能持有多个实例,比如一个集合。啊,我明白了!代码中还有另一个对象引用了TempStock,因此在“New”之后不会立即调用析构函数,而是在该引用终止时调用析构函数。
Option Explicit

Sub Stocks()

Dim oCollection         As Collection
Dim TempStock           As Stock
Dim lCnt                As Long


Set oCollection = New Collection

For lCnt = 1 To 5

    Set TempStock = New Stock

    TempStock.Set_Stock ("Stock_" & lCnt)       'sets TempStock name eg. 
    oCollection.Add TempStock
Next lCnt

End Sub