Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array as a Class Member

I'm designing a dynamic buffer for outgoing messages. The data structure takes the form of a queue of nodes that have a Byte Array buffer as a member. Unfortunately in VBA, Arrays cannot be public members of a class.

For example, this is a no-no and will not compile:

'clsTest

Public Buffer() As Byte

You will get the following error: "Constants, fixed-length strings, arrays, user-defined types and Declare statements not allowed as Public members of object modules"

Well, that's fine, I'll just make it a private member with public Property accessors...

'clsTest

Private m_Buffer() As Byte

Public Property Let Buffer(buf() As Byte)
    m_Buffer = buf
End Property

Public Property Get Buffer() As Byte()
    Buffer = m_Buffer
End Property

...and then a few tests in a module to make sure it works:

'mdlMain

Public Sub Main()
    Dim buf() As Byte
    ReDim buf(0 To 4)

    buf(0) = 1
    buf(1) = 2
    buf(2) = 3
    buf(3) = 4


    Dim oBuffer As clsTest
    Set oBuffer = New clsTest

    'Test #1, the assignment
    oBuffer.Buffer = buf    'Success!

    'Test #2, get the value of an index in the array
'    Debug.Print oBuffer.Buffer(2)   'Fail
    Debug.Print oBuffer.Buffer()(2)    'Success!  This is from GSerg's comment

    'Test #3, change the value of an index in the array and verify that it is actually modified
    oBuffer.Buffer()(2) = 27
    Debug.Print oBuffer.Buffer()(2)  'Fail, diplays "3" in the immediate window
End Sub

Test #1 works fine, but Test #2 breaks, Buffer is highlighted, and the error message is "Wrong number of arguments or invalid property assignment"

Test #2 now works! GSerg points out that in order to call the Property Get Buffer() correctly and also refer to a specific index in the buffer, TWO sets of parenthesis are necessary: oBuffer.Buffer()(2)

Test #3 fails - the original value of 3 is printed to the Immediate window. GSerg pointed out in his comment that the Public Property Get Buffer() only returns a copy and not the actual class member array, so modifications are lost.

How can this third issue be resolved make the class member array work as expected?

(I should clarify that the general question is "VBA doesn't allow arrays to be public members of classes. How can I get around this to have an array member of a class that behaves as if it was for all practical purposes including: #1 assigning the array, #2 getting values from the array, #3 assigning values in the array and #4 using the array directly in a call to CopyMemory (#3 and #4 are nearly equivalent)?)"

like image 898
Blackhawk Avatar asked Aug 15 '14 15:08

Blackhawk


People also ask

How do you declare an array as a class member in C++?

Anyway, here is how you do it within the class: class Test { public: int a; int * b; Test(int Ia=1) { a = Ia; b = new int[a]; } ~Test() { delete[] b; } }; See delete vs delete[] operators in C++ for why to use delete[] instead of delete in the destructor. Don't forget the rule of three.

How do you declare an array in class?

Syntax: Class_Name obj[ ]= new Class_Name[Array_Length]; For example, if you have a class Student, and we want to declare and instantiate an array of Student objects with two objects/object references then it will be written as: Student[ ] studentObjects = new Student[2];

How do you initialize an array inside a class?

One way to initialize the array of objects is by using the constructors. When you create actual objects, you can assign initial values to each of the objects by passing values to the constructor. You can also have a separate member method in a class that will assign data to the objects.


1 Answers

So it turns out I needed a little help from OleAut32.dll, specifically the 'VariantCopy' function. This function faithfully makes an exact copy of one Variant to another, including when it is ByRef!

'clsTest

Private Declare Sub VariantCopy Lib "OleAut32" (pvarDest As Any, pvargSrc As Any)

Private m_Buffer() As Byte

Public Property Let Buffer(buf As Variant)
    m_Buffer = buf
End Property

Public Property Get Buffer() As Variant
    Buffer = GetByRefVariant(m_Buffer)
End Property

Private Function GetByRefVariant(ByRef var As Variant) As Variant
    VariantCopy GetByRefVariant, var
End Function

With this new definition, all the tests pass!

'mdlMain

Public Sub Main()
    Dim buf() As Byte
    ReDim buf(0 To 4)

    buf(0) = 1
    buf(1) = 2
    buf(2) = 3
    buf(3) = 4


    Dim oBuffer As clsTest
    Set oBuffer = New clsTest

    'Test #1, the assignment
    oBuffer.Buffer = buf    'Success!

    'Test #2, get the value of an index in the array
    Debug.Print oBuffer.Buffer()(2)    'Success!  This is from GSerg's comment on the question

    'Test #3, change the value of an index in the array and verify that it is actually modified
    oBuffer.Buffer()(2) = 27
    Debug.Print oBuffer.Buffer()(2)  'Success! Diplays "27" in the immediate window
End Sub
like image 157
Blackhawk Avatar answered Sep 23 '22 12:09

Blackhawk