locked
Prevent objects derived from same base class from QI to one another. RRS feed

  • Question

  • I have VB COM classes B and C derived from class A, which is not COM, simplified below to demo my problem.  Further below is some test VBA.  When I create a B object and pass into the Test subroutine, I want the Set z and Set zz to succeed, since the object is a B and derives from A.  But I do not want the Set zzz to succeed since the passed object is not a C.

    How do I solve this ?

    [ I have found that I can garbage up B and C adding a unique (unnecessary) Public method to each, but these got to be a better way ?  Maybe to mark the classes in some way. ]

    Public Interface ITest
        Function IsValid() As Boolean
    End Interface
    
    Public MustInherit Class A
        Implements ITest
        Protected MustOverride ReadOnly Property MyDataFit() As Double()
    
        Public Function IsValid() As Boolean Implements ITest.IsValid
            Return UBound(MyDataFit) = 2
        End Function
    End Class
    
    <ComClass(B.ClassId)> Public Class B
        Inherits A
    
    #Region "COM GUIDs"
        Public Const ClassId As String = ""
    #End Region
    
        Public Sub New()
            MyBase.New()
        End Sub
    
        Private vMyDataFit() As Double = {1.0001, 0.9937, 0.5674}
    
        Protected Overrides ReadOnly Property MyDataFit() As Double()
            Get
                Return vMyDataFit
            End Get
        End Property
    End Class
    
    <ComClass(C.ClassId)> Public Class C
        Inherits A
    
    #Region "COM GUIDs"
        Public Const ClassId As String = ""
    #End Region
    
        Public Sub New()
            MyBase.New()
        End Sub
    
        Private vMyDataFit() As Double = {1.0001, 0.9948, 0.4419}
    
        Protected Overrides ReadOnly Property MyDataFit() As Double()
            Get
                Return vMyDataFit
            End Get
        End Property
    
    End Class
    Option Explicit
    
    Sub Test1()
        Dim o As B
        Set o = New B
        Test o
    End Sub
    
    Sub Test2()
        Dim o As C
        Set o = New C
        Test o
    End Sub
    
    Private Sub Test(o As Object)
        Dim z As A, zz As B, zzz As C, nFails As Integer
        On Error Resume Next
        Set z = o
        Debug.Assert Err.Number = 0
        Err.Clear
        '
        ' Desire one of these to fail !!
        '
        Set zz = o
        If Err.Number <> 0 Then nFails = nFails + 1
        Err.Clear
        
        Set zzz = o
        If Err.Number <> 0 Then nFails = nFails + 1
        Err.Clear
    
        Debug.Assert nFails = 1
    End Sub


    • Moved by Mike Feng Tuesday, April 17, 2012 6:23 AM VBA (From:Visual Basic General)
    Thursday, April 12, 2012 4:39 PM

All replies

  • Not the place to get answers to VBA questions - this is VB.Net forum. Is an Excel/Access/Word forum more appropriate?

    However, is there not a typeof method? Vaguely recall something that lets you find type of an object but not done VBA for over a decade.


    Regards David R
    ---------------------------------------------------------------
    The great thing about Object Oriented code is that it can make small, simple problems look like large, complex ones.
    Object-oriented programming offers a sustainable way to write spaghetti code. - Paul Graham.
    Every program eventually becomes rococo, and then rubble. - Alan Perlis
    The only valid measurement of code quality: WTFs/minute.

    Thursday, April 12, 2012 5:28 PM
  • Hello nice that you made this testable sample, 

    But to do this we have now to build it. Create and register a com object, and then use VBA which is for many (most) of us not our style.

    Can you not make the same sample project without the Com attributes but a normal classes and with a test procedure in VB Net. 

    Most probably you get then an answer, at least I don't go that way by creating first a VBA enviroment to test your problem or registering all kind of Com objects in my computer.

    In my idea is the by you stated problem not depending from the fact if it is Com or VBA but simply an how to make a right class implementation (or whatever you call it).

    If I'm wrong correct me, no problem. (I ask this to the OP)

     


    Success
    Cor

    Thursday, April 12, 2012 6:05 PM
  • It looks to me like you want an error to be implictly thrown when an inheritor creates a state that the base class considers invalid.  I see a few things wrong with what you are doing:

    1. For the fail count to be incremented you would need an exception to be thrown (thus the err,number being non-zero)...  you are not throwing errors anywhere so I fail to see how you expect this to work.  What error are you expecting to catch?
    2. You IsValid property is presumably the way you woudl know if the inheriting class is in an invalid state, yet you are not using it either in your inheriting classes nor in your tests.  If anything you should change your err test to this:  If o.IsValid = False Then nFails = nFails + 1
    Thursday, April 12, 2012 7:26 PM
  • To Riced: Unfortunately VBA TypeOf is failing is distinguish between B and C.  Distinguishment is what I want and as I suggested, I can create unique public methods in both B and C and achieve a hamhandled sucess.

    To Dig-Boy: I expect the same implicit throw that I would get if I passed an unrelated object into the Test subroutine (example below where I would get nFails = 2).

    As for item 2, the actual base class A is written as a calculation engine (to implement an interface exposed on a native code type library).  The IsValid (and other methods I left out) is called by the native code program, not necessarily by the VBA side.  Class A may contain additional methods for use of the VBA side.  The B and C classes only contain the data necessary to steer the calculation engine in the B or C direction.  I suppose I could place a Public MustOverride Property MyType as String on A to tell me whether it's really a B or a C, but this too seems hamhanded.

    Sub Test3()
        Dim o As Excel.Application
        Set o = Excel.Application
        Test o
    End Sub

    Thursday, April 12, 2012 8:18 PM