首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >VBA中操作符重载的解决方法

VBA中操作符重载的解决方法
EN

Stack Overflow用户
提问于 2019-03-29 10:19:48
回答 1查看 245关注 0票数 2

我需要在VBA中创建一个新的类,它可以支持一些基本的数学操作(加、乘等)。在VBA中不允许操作符重载,因此,为此,我考虑创建以下接口

INumeric

代码语言:javascript
复制
Public Function Add(ByVal other As INumeric) As INumeric
End Function

Public Function Multiply(ByVal other As INumeric) As INumeric
End Function

Public Function Negative() As INumeric
End Function

'[...] etc

它定义了对我想使用的所有操作符(+-^%等)的响应。也许每个接口都有一个单独的接口,或者一个鸭子类型的松散接口(即,只需定义一个.Add方法像蟒蛇一样,而不是Implements)。

这可与数学课结合使用,以取代运算符的功能:

Maths

代码语言:javascript
复制
Option Explicit
'@PredeclaredID

Public Function Add(ByVal first As Variant, ByVal second As Variant) As Variant
    
    If TypeOf first Is INumeric Then
        On Error GoTo defaultAdd
            Dim numericFirst As INumeric
            Set numericFirst = first
            Set Add = numericFirst.Add(second)

    ElseIf TypeOf second Is INumeric Then
        On Error GoTo defaultAdd
            Dim numericSecond As INumeric
            Set numericSecond = second
            Set Add = numericSecond.Add(first)

    Else
defaultAdd:
        On Error GoTo -1
        On Error GoTo errHandle
            Add = first + second
    End If
    Exit Function
    
errHandle:
    err.Description = "Arguments couldn't be added :( try implementing INumeric"
    err.Raise 5
End Function

Public Function Negate(ByVal value As Variant) As Variant
    'Similar sort of stuff
End Function

'[...] etc

然后在我的代码里

代码语言:javascript
复制
Dim result As Variant
Set result = Maths.Add(INumeric1, INumeric2) 'returns INumeric probably
result = Maths.Add(IsNumeric1, IsNumeric2) 'returns IsNumeric probably

其中IsNumeric1只表示定义了+运算符的值-例如LongDouble (甚至是String__;"3“+ "4”= "34“ofc!)

正如您所看到的,这变得非常快,特别是如果我想实现10+操作符的话。就这一点而言,VBA Math库的其余部分--我目前的方法似乎很冗长,而且并不特别枯燥。

,所以我想知道是否有什么库可以添加到我的VBA项目中,它定义了类似于这些接口的接口,并将它们用于数学或逻辑方程中?或者说有点不同,并避免了一个X问题;,我如何能够创建自定义数据类型,可以直接用于一般的数学表达式?,我可以想象创建类来定义它们对操作的响应,但我对其他方法开放。

附录

FWIW,我创建了一个示例实现类(还为Create ( the;)方法预先声明)。它代表了一种科学的测量方法,它具有价值和不确定性。

代码语言:javascript
复制
Option Explicit
'@PredeclaredID

Implements INumeric

Public value As Double
Private uncertainty As Double

Public Function Take(ByVal apparentValue As Double, Optional ByVal absErr As Double = 0, Optional ByVal relErr As Double = 0) As Measurement
    With New Measurement
        .value = apparentValue
        If absErr <> 0 Then
            .absoluteErr = absErr
        ElseIf relErr <> 0 Then
            .relativeErr = relErr
        Else
            'must be a perfect number, no errors
            .absoluteErr = 0 'default value so no point
        End If
        Set Take = .Self
    End With
End Function

Public Property Get relativeErr() As Double
    relativeErr = Abs(uncertainty / value)
End Property

Public Property Let relativeErr(ByVal relErr As Double)
    uncertainty = relErr * value
End Property

Public Property Get absoluteErr() As Double
    absoluteErr = Abs(uncertainty)
End Property

Public Property Let absoluteErr(ByVal absErr As Double)
    uncertainty = absErr
End Property

Public Property Get Self() As Measurement
    Set Self = Me
End Property

Public Function toString(Optional ByVal formatWithRelErr As Boolean = True) As String
    If formatWithRelErr Then
        toString = value & "±" & Me.relativeErr * 100 & "%"
    Else
        toString = value & "±" & Me.absoluteErr
    End If
End Function

Private Function INumeric_Add(ByVal other As Variant) As INumeric
    If TypeOf other Is Measurement Then
        Set INumeric_Add = Measurement.Take(Me.value + other.value, absErr:=Me.absoluteErr + other.absoluteErr)
    Else
        Set INumeric_Add = Maths.Add(Me, Measurement.Take(other))
        'or Set INumeric_Add = Measurement.Take(Me.value + other, absErr:=Me.absoluteErr)
    End If
End Function

Private Function INumeric_Multiply(ByVal other As Variant) As INumeric
    If TypeOf other Is Measurement Then
        Set INumeric_Multiply = Measurement.Take(Me.value * other.value, relErr:=Me.relativeErr + other.relativeErr)
    Else
        Set INumeric_Multiply = Maths.Multiply(Me, Measurement.Take(other))
    End If
End Function

Private Function INumeric_Negative() As INumeric
    Set INumeric_Negative = Measurement.Take(-Me.value, absErr:=Me.absoluteErr)
End Function

并且可以用这个来测试

代码语言:javascript
复制
Sub test()
    Dim a As Measurement, b As Measurement, c As Integer
    Set a = Measurement.Take(10, absErr:=1)
    Set b = Measurement.Take(15, relErr:=0.2)
    c = 3 'treated equiv to Measurement.Take(3, relErr = 0)
    
    Debug.Print "a = "; a.toString; " = "; a.toString(False)
    Debug.Print "b = "; b.toString; " = "; b.toString(False)
    Debug.Print "c ="; c

    Dim aPlusB As Measurement
    Set aPlusB = Maths.Add(a, b)
    Debug.Print "a + b = "; aPlusB.toString
    
    Dim bPlusC As Measurement
    Set bPlusC = Maths.Add(c, b)
    Debug.Print "b + c = "; bPlusC.toString(formatWithRelErr:=False)

    Debug.Print "3.2 + 7.3 ="; Maths.Add(3.2, 7.3)
    
    On Error Resume Next
        Debug.Print Maths.Add("k", 4)
        If err.Number <> 0 Then Debug.Print "Err:"; err.Number; "- "; err.Description
End Sub

它输出这个

代码语言:javascript
复制
a = 10±10% = 10±1
b = 15±20% = 15±3
c = 3
a + b = 25±16%
b + c = 18±3
3.2 + 7.3 = 10.5 
Err: 5 - Arguments couldn't be added :( try implementing INumeric
EN

回答 1

Stack Overflow用户

发布于 2019-03-29 10:59:36

不确定我是否在同一页面上,但您可以在clsMaths中按照以下思路做一些事情

代码语言:javascript
复制
Private colNumbersForOperation As Collection

Public Enum enmOperations
    enmSum = 1
    enmMult = 2
    enmDivide = 3
End Enum

Private Sub class_initialize()

    Set colNumbersForOperation = New Collection

End Sub

Public Function Load_Number_To_Collection(varEntry As Variant) As Collection

Dim c As Excel.Range

    If TypeOf varEntry Is Excel.Range Then
        For Each c In varEntry.Cells
            colNumbersForOperation.Add c.Value
        Next c
    Else
        colNumbersForOperation.Add varEntry
    End If

End Function

Public Function OperateOnNumbers(enmOperation As enmOperations) As Double

Dim v As Variant

For Each v In colNumbersForOperation
    Select Case enmOperation
        Case enmSum
            OperateOnNumbers = OperateOnNumbers + v
        Case enmMult
            OperateOnNumbers = IIf(OperateOnNumbers = 0, v, OperateOnNumbers * v)
        Case enmDivide
            OperateOnNumbers = IIf(OperateOnNumbers = 0, v, OperateOnNumbers / v)
        Case Else
    End Select
Next v


End Function

这可以像这样使用

代码语言:javascript
复制
Dim c As New clsMaths

c.Load_Number_To_Collection 10
c.Load_Number_To_Collection 20
c.Load_Number_To_Collection Range("a1:a10")

Debug.Print c.OperateOnNumbers(enmSum)
Debug.Print c.OperateOnNumbers(enmMult)
Debug.Print c.OperateOnNumbers(enmDivide)
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55415216

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档