VB6对象和数据类型

7
我了解在面向对象的编程语言(例如Java)中,Object类位于类层次结构的顶部。我也了解.NET中有引用类型和值类型,以及C语言中的类型定义。
尽管如此,我仍然不理解VB6中的Object是什么(请参见http://msdn.microsoft.com/en-us/library/aa338034%28v=vs.60%29.aspx),以及Variant到底是什么。Variant是什么?在VB6中,Object是如何实现的?

一个VB6的Variant包含了一个在http://msdn.microsoft.com/en-us/library/aa908601.aspx中描述的结构。 - Bob77
2个回答

10

VB6使用的所有对象都是COM对象。COM对象本质上是一个可变长度的数据结构,其可变长度的头包含任意数量的指向VTables的32位指针,后续字节包含对象的实例数据。例如:

Bytes
0-3    VTable1 pointer
4-7    VTable2 pointer
8-11   VTable3 pointer
...
       Instance data

VTable是一个包含32位指向函数的指针数组,所有这些函数都会传递一个"this"实例指针。

Bytes
0-3    Func1(this, ..., ...)
4-7    Func2(this, ..., ...)
8-11   Func3(this, ..., ...)
...

唯一的其他规范是所有的VTable 必须 继承自IUnknown,也就是说前三个函数必须是:

QueryInterface()
AddRef()
Release()

QueryInterface() 函数能够让你查询一个 COM 对象是否支持某个特定接口(由 UUID 表示)。AddRef() 函数允许对象写入者增加内部引用计数器。Release() 函数允许对象写入者减少引用计数器,并且在计数器归零时销毁该对象。在 VB 中,你不需要直接调用这些方法 - 编译器会为你添加这些调用(这是 VB6 的优点之一)。

更多详情请查看http://msdn.microsoft.com/en-us/library/windows/desktop/ms680509(v=vs.85).aspx

VB 中的“Object”类型是对支持 IDispatch 接口的对象的引用(请参见http://msdn.microsoft.com/en-us/library/windows/desktop/dd318520(v=vs.85).aspx)。这就是你能够在 VB 和 VBScript 中使用后期绑定(late binding)的原因。所有使用 VB6 编写的对象都自动实现了从 IDispatch 继承的接口。这被称为双重接口,因为它同时支持早期和后期绑定。

注意,COM 中没有直接的类型系统。但是,你可以选择支持 ITypeInfo 接口,以允许你的对象的用户访问你想要添加到该对象的信息(使用默认实现使用类型库来存储此信息更容易)。

正如 Bob Riemersma 所提到的那样,Variant 类型实际上是一个 16 字节的结构,其中有一个 2 字节的整数(vt),表示被封装的 Automation 类型,后面的 8 字节可以用于包含高达 8 字节的值类型或指向另一类型的 32 位指针。VB 使用其内部函数在 VB 类型和 Variant 之间进行所有必要的转换,并进行所有必要的内存分配和释放。变体可以通过将对象的指针复制到该变量中并调用该对象的 AddRef() 方法来包含对 COM 对象的引用。


我能想到的唯一有用的补充是强调VB仅直接支持公开双重接口的COM对象,因为它不想涉及区分支持和不支持后期绑定的对象的混浊世界。另一方面,这并不是一个严格的限制,因为可以通过使用SendMessage和EM_GETOLEINTERFACE与iUnknown类型的变量来获取独占早期绑定COM类的接口。 - BobRodes

5
让我把这些问题分开解释一下:
首先,VB6不是VB.Net,也不使用.Net框架,而是使用较旧的COM框架。(无法确定您是否已经知道这一点)。
其次,您链接到的是VB6内置的“类”(Classes),即使它们被称为“对象”。他们的术语有些草率。
第三,可能最重要的是,在VB6中,并非所有数据都是对象,而且对象甚至不是默认或主要的数据类型。实际上,VB6中的数据类型类似于.Net的值类型,但少得多(大多数甚至没有运行时类型容器,只有内存地址)。
因此,大多数数据项都不是对象,因此没有类,因此没有任何继承,因此不派生自其他任何东西,因此没有“类型层次结构”,因此不能有任何处于其类型层次结构“顶部”的东西(尽管那些类/对象确实拥有所有这些)。因此,您没有基础/根数据类型可用于任何其他数据类型,这将成为各种参数传递等情况的问题。
变体(Variant)是早期解决此问题的一种方法,在VB之前的版本中实现了(早于VB中的对象)。变体只是一个动态描述符,包装另一个任何数据类型的项目。当您使用它时,它(通常)就像您直接使用其包含的内容一样,但实际上您是通过变体获取其当前包含的任何类型的数据项。
变体本身会跟踪其内容的数据类型,并使访问它的VB代码以不同/适当的方式行事(一种原始的多态性)。
如果这听起来很笨拙并且有很多开销,那么确实如此。但在当时,当您需要处理“任何数据类型”时,它是最好的可用解决方案。

我意识到VB6是一种基于COM的语言,而不是基于.NET框架的。我的问题特别涉及变量。 - w0051977

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接