2017-02-14 3 views
2

Ich fange gerade an, Klassen in VBA zu verwenden, und ich folge der Methode "Vererbung durch Konstruktion", die here beschrieben wird. In meinem Beispiel wird eine einfache Klasse verwendet, die einen Wert (als Variante) und einen Werttyp (als Zeichenfolge) enthält. Ich habe eine Unterklasse erstellt, in der der Werttyp im Konstruktor auf string gesetzt ist. Hier ist mein Code:VBA-Vererbung über Konstruktion, Konstruktor nicht funktioniert?

Interface-Klasse (IVal)

'IVal interface class (from https://www.theartofquantfinance.com/inheritance-by-construction-in-vba/) 
Option Explicit 

'----------------------------------- 
'Accessor methods for ValType 
'----------------------------------- 
Public Property Get ValType() As String 
End Property 
Public Property Let ValType(ByVal RHS As String) 
End Property 
'----------------------------------- 
'Accessor methods for Val 
'----------------------------------- 
Public Property Get Val() As Variant 
End Property 
Public Property Let Val(ByVal RHS As Variant) 
End Property 

'Add other methods here as "Public Sub" 
'i.e. 
'Public Sub HonkHorn() 
'End Sub 

Basisklasse (CBaseVal)

'CBaseVal base class - implements IVal interface (from https://www.theartofquantfinance.com/inheritance-by-construction-in-vba/) 
Option Explicit 
Implements IVal 

'------------------------------ 
'Private Fields 
'------------------------------ 
Private valType_ As String 
Private val_ As Variant 

'------------------------------ 
'Constructors and destructors 
'------------------------------ 
Private Sub Class_Initialization() 
    valType_ = "Base Val" 
    val_ = Nothing 
End Sub 
'------------------------------ 
'Class Properties And methods - public, visible to all modules 
'These would be declared in the interface class 
'------------------------------ 
Public Property Get ValType() As String 
    ValType = valType_ 
End Property 
Public Property Let ValType(ByVal RHS As String) 
    valType_ = RHS 
End Property 

Public Property Get Val() As Variant 
    Val = val_ 
End Property 
Public Property Let Val(ByVal RHS As Variant) 
    val_ = RHS 
End Property 

'Add additional class methods here 
'e.g. 
'Public Sub HonkHorn() 
' MsgBox prompt:="Beep!!!" 
'End Sub 

'------------------------------ 
'Interface property and method implementation - private, only visible to this module 
'Delegate interface properties and methods to this (base) class using "Me" 
'------------------------------ 
Private Property Let IVal_Val(ByVal RHS As Variant) 
    Me.Val = RHS 
End Property 

Private Property Get IVal_Val() As Variant 
    IVal_Val = Me.Val 
End Property 

Private Property Let IVal_ValType(ByVal RHS As String) 
    Me.ValType = RHS 
End Property 

Private Property Get IVal_ValType() As String 
    IVal_ValType = Me.ValType 
End Property 

'End Property 
'Add additional IF methods here 
'i.e. 
'Private Sub ICar_HonkHorn() 
' Call Me.HonkHorn 
'End Sub 

Child-Klasse (CStringVal)

'CStringVal class - implements IVal interface and delegates to CVal as appropriate (from https://www.theartofquantfinance.com/inheritance-by-construction-in-vba/) 
Option Explicit 
Implements IVal 

'------------------------------ 
'Private Fields 
'------------------------------ 
Private baseVal_ As IVal 'contains an instance of the IVal class (why isn't this "As CBaseVal"?) 

'------------------------------ 
'Constructors and destructors 
'------------------------------ 
Private Sub Class_Initialization() 
    Set baseVal_ = New CBaseVal 'initialize private field of type "val class" 
    baseVal_.ValType = "string" 
    baseVal_.Val = Nothing 
End Sub 
'------------------------------ 
'Class Properties And methods (here's where you over-ride the base class implementation) 
'These would be declared in the base class and the interface implementation below will delegate to either here or base class 
'------------------------------ 
'e.g. 
'Public Sub HonkHorn() 
' MsgBox prompt:="Beep!!!" 
'End Sub 


'------------------------------ 
'Interface property and method implementation - declared in base class and either: 
'=> most delegate to base class 
'=> some may override base class and delegate here 
'------------------------------ 
Private Property Let IVal_Val(ByVal RHS As Variant) 
    baseVal_.Val = RHS 'Delegate to base class 
End Property 

Private Property Get IVal_Val() As Variant 
    IVal_Val = baseVal_.Val 
End Property 

Private Property Let IVal_ValType(ByVal RHS As String) 
    baseVal_.Val = RHS 'Delegate to base class 
End Property 

Private Property Get IVal_ValType() As String 
    IVal_ValType = baseVal_.ValType 'Delegate to base class 
End Property 

'Add additional interface methods here 
'i.e. 
'Private Sub ICar_HonkHorn() 
' Call Me.HonkHorn 'Overrides base class implementation, delegates to class method above 
'End Sub 

Und hier ist der Code Ich benutze es zu testen:

Public Sub testStringValClass() 
    Dim interfaceClassVal As IVal 
    Dim baseClassVal As CBaseVal 
    Dim stringClassVal As CStringVal 

    Set interfaceClassVal = New IVal 
    Set baseClassVal = New CBaseVal 
    Set stringClassVal = New CStringVal 

    a = interfaceClassVal.ValType 
    b = baseClassVal.ValType 
    c = stringClassVal.ValType 
End Sub 

Das erste Problem ist ein Übersetzungsfehler, dass für die Zeile „Methode oder Datenelement nicht gefunden“

c = stringClassVal.ValType 

Wenn ich diese Zeile auskommentieren, der Code ausgeführt wird, aber Uhren mit scheint es, dass valType_ nicht wird set, entweder als "Base Val" für das Basisklassenobjekt oder als "String" für das String-Klassenobjekt. Darüber hinaus gibt es „Objektvariable oder With-Blockvariable nicht festgelegt“ Fehler für die folgenden Eigenschaften:

stringClassVal.IVal_Val 
stringClassVal.IVal_ValType 

ich ratlos hier Art bin ... gehe ich davon aus, es ist einfach so etwas wie ein Rechtschreibfehler, aber ich kann Ich finde es nicht.

+1

'Class_Initialize()' nicht 'Class_Initialization()' –

Antwort

1

Das ist einfach, weil Ihre Klasse CStringVal die Eigenschaft ValType nicht implementiert. Ok, du hast die Eigenschaft ValType der Schnittstelle IVal implementiert aber nicht die explizite ValType der Klasse selbst.

Um auf die Methode der Schnittstelle zuzugreifen, müssen Sie irgendwie zu cast Ihr Objekt zum Typ der Schnittstelle. Zum Beispiel:

Dim itf As IVal 
Dim stringClassVal As New CStringVal 
Set itf = stringClassVal '<-- casts the object to the interface's type 
' and now: 
c = itf.ValType 

oder können Sie die definierten Namen verwenden:

c = stringClassVal.IVal_ValType 

Aber bemerken Sie nicht die Felder der Variablen initialisiert haben noch (die Buchstaben vor dem Getter verwenden).

Ja, Vererbung in VBA/VB6 ist irgendwie schwierig und nicht sehr natürlich. Wenn eine Klasse eine Schnittstelle implementiert, sind die Schnittstelle der Methoden an die Schnittstelle ein Verweis zugänglich durch, nicht auf die Implementierer Objekt, es sei denn, letztere ausdrücklich die

Methode/Eigenschaft definiert

Beachten Sie auch, dass die initializer val_ = Nothing nutzlos ist und irgendwie falsch. Ein nicht initialisiertes Variant wird als empty Variante erstellt. Nothing wird grundsätzlich für Objekte verwendet, nicht für Basisvariablen (einschließlich Strings).

Auch als @TimWilliams sagte der Name des Konstruktors ist Class_Initialize nicht Class_Initialization.

+0

Lassen Sie mich ein paar Nachfragen stellen: (1) Was ist der beste Weg, um Follow-up-Fragen zu stellen? (2) Ist es die Mühe wert, Klassen zu verwenden, da VBA polymorph herausgefordert ist? –

+0

@JamesAlesi (1) können Sie hier natürlich Nachfragen stellen. (2) Für diese Art von Aufgaben sind Klassen nicht der richtige Weg, und sicher nicht Schnittstellen. Klassen sind nützlich, wenn Sie über ausreichend Objekte verfügen, die den Status halten und viele zustandsabhängige Aktionen ausführen. Schnittstellen sind nützlich für das Löschen von Typen, das heißt, wenn Sie verschiedene Dinge haben, die dieselbe Liste von Aktionen ausführen, aber jede auf ihrem eigenen Weg, und diese verschiedenen Objekte können sich in einem Container befinden. Nichts davon wird in Ihrem beabsichtigten Anwendungsfall benötigt. Hoffe das klärt sich :) –

+0

Daher sind Klassen keine natürliche Wahl, um mit VBA zu programmieren, obwohl sie gelegentlich nützlich sein können. –

Verwandte Themen