subclassing

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • =?Utf-8?B?QmV0aA==?=

    subclassing

    Hello.

    I'm trying to figure out how to create subclasses with properties specific
    to the subclass and so far it isn't going well.

    Right now I have a class with an enum representing the type. The class has
    all the properties specific to all the types, but what I want instead is to
    move those properties to subclasses specific to each type.

    I have code like this:

    Friend Class ValidateValue
    Private _textMaxLen As Integer
    Private _textMinLen As Integer
    Private _validateType As validateTypes

    Friend Sub New(ByVal validate As String)
    Dim compoundType As String
    Dim remainder As String
    Dim openParenPos As Integer
    Dim commaPos As Integer

    openParenPos = InStr(validate, "(")
    If openParenPos 0 Then
    compoundType = Mid(validate, 1, openParenPos - 1)
    remainder = Mid(validate, openParenPos + 1)
    remainder = Mid(remainder, 1, Len(remainder) - 1) ' strip closing paren
    Select Case compoundType
    Case "text", "textnum"
    If compoundType = "text" Then
    _validateType = validateTypes.t ext
    Else
    _validateType = validateTypes.t extNum
    End If
    commaPos = InStr(remainder , ",")
    If commaPos = 0 Then
    _textMaxLen = CInt(remainder)
    Else
    _textMaxLen = CInt(Mid(remain der, 1, commaPos - 1))
    _textMinLen = CInt(Mid(remain der, commaPos + 1))
    End If

    But since the maxLen and minLen properties are specific to the two text
    types, what I want to do is declare a subclass which inherits from the
    existing class and contains and sets the validateType, textMaxLen, and
    textMinLen properties given the compoundType and remainder.

    The problem I'm having is with the subclass's constructor. In the subclass,
    I want to pass the compoundType and remainder, and have code like:
    'Friend Class ValidateText
    ' Inherits ValidateValue

    ' Private _textMaxLen As Integer
    ' Private _textMinLen As Integer
    ' Private _validateType As validateTypes

    ' Friend Sub New(ByVal compoundType As String, ByVal remainder As String)
    ' Dim commaPos As Integer
    ' If compoundType = "text" Then
    ' _validateType = validateTypes.t ext
    ' Else
    ' _validateType = validateTypes.t extNum
    ' End If
    ' commaPos = InStr(remainder , ",")
    ' If commaPos = 0 Then
    ' _textMaxLen = CInt(remainder)
    ' Else
    ' _textMaxLen = CInt(Mid(remain der, 1, commaPos - 1))
    ' _textMinLen = CInt(Mid(remain der, commaPos + 1))
    ' End If
    ' End Sub

    But that doesn't work because the base class doesn't have a constructor
    without parameters. I want to use a parameter into a base class as a key to
    determine the subclass to create and then create one of my subclasses.

    I'm thinking in the base class I need a variable like:
    Private _child as ValidateValue

    And in the base class's constructor, have code like:
    Select Case compoundType
    Case "text", "textnum"
    _child = new ValidateText(co mpoundType, remainder)

    But I can't get the subclass to work.

    What should I be doing differently?

    Thanks for any help,

    -Beth
  • Family Tree Mike

    #2
    Re: subclassing

    Well, is there a reason you don't want an empty constructor in
    ValidateValue? You don't necessarily have to call it. After that, it seems
    like you probably meant to have _textMaxLen, _textMinLen and _validateType
    be protected, not private.

    "Beth" <Beth@discussio ns.microsoft.co mwrote in message
    news:05260BDC-07F9-41A4-A531-1CB242743D6B@mi crosoft.com...
    Hello.
    >
    I'm trying to figure out how to create subclasses with properties specific
    to the subclass and so far it isn't going well.
    >
    Right now I have a class with an enum representing the type. The class
    has
    all the properties specific to all the types, but what I want instead is
    to
    move those properties to subclasses specific to each type.
    >
    I have code like this:
    >
    Friend Class ValidateValue
    Private _textMaxLen As Integer
    Private _textMinLen As Integer
    Private _validateType As validateTypes
    >
    Friend Sub New(ByVal validate As String)
    Dim compoundType As String
    Dim remainder As String
    Dim openParenPos As Integer
    Dim commaPos As Integer
    >
    openParenPos = InStr(validate, "(")
    If openParenPos 0 Then
    compoundType = Mid(validate, 1, openParenPos - 1)
    remainder = Mid(validate, openParenPos + 1)
    remainder = Mid(remainder, 1, Len(remainder) - 1) ' strip closing paren
    Select Case compoundType
    Case "text", "textnum"
    If compoundType = "text" Then
    _validateType = validateTypes.t ext
    Else
    _validateType = validateTypes.t extNum
    End If
    commaPos = InStr(remainder , ",")
    If commaPos = 0 Then
    _textMaxLen = CInt(remainder)
    Else
    _textMaxLen = CInt(Mid(remain der, 1, commaPos - 1))
    _textMinLen = CInt(Mid(remain der, commaPos + 1))
    End If
    >
    But since the maxLen and minLen properties are specific to the two text
    types, what I want to do is declare a subclass which inherits from the
    existing class and contains and sets the validateType, textMaxLen, and
    textMinLen properties given the compoundType and remainder.
    >
    The problem I'm having is with the subclass's constructor. In the
    subclass,
    I want to pass the compoundType and remainder, and have code like:
    'Friend Class ValidateText
    ' Inherits ValidateValue
    >
    ' Private _textMaxLen As Integer
    ' Private _textMinLen As Integer
    ' Private _validateType As validateTypes
    >
    ' Friend Sub New(ByVal compoundType As String, ByVal remainder As String)
    ' Dim commaPos As Integer
    ' If compoundType = "text" Then
    ' _validateType = validateTypes.t ext
    ' Else
    ' _validateType = validateTypes.t extNum
    ' End If
    ' commaPos = InStr(remainder , ",")
    ' If commaPos = 0 Then
    ' _textMaxLen = CInt(remainder)
    ' Else
    ' _textMaxLen = CInt(Mid(remain der, 1, commaPos - 1))
    ' _textMinLen = CInt(Mid(remain der, commaPos + 1))
    ' End If
    ' End Sub
    >
    But that doesn't work because the base class doesn't have a constructor
    without parameters. I want to use a parameter into a base class as a key
    to
    determine the subclass to create and then create one of my subclasses.
    >
    I'm thinking in the base class I need a variable like:
    Private _child as ValidateValue
    >
    And in the base class's constructor, have code like:
    Select Case compoundType
    Case "text", "textnum"
    _child = new ValidateText(co mpoundType, remainder)
    >
    But I can't get the subclass to work.
    >
    What should I be doing differently?
    >
    Thanks for any help,
    >
    -Beth

    Comment

    • =?Utf-8?B?T21lZ2FTcXVhcmVk?=

      #3
      RE: subclassing

      Hello, Beth,

      You can call your base class's constructor (with an argument for the
      validate parameter) as the first executable line of the inherited classes
      constructor.

      Also, as Mike says, you probably want the mentioned variables to be
      Protected (not private) and then remove the corresponding declarations from
      the inherited class.

      Cheers,
      Randy

      Comment

      • =?Utf-8?B?QmV0aA==?=

        #4
        Re: subclassing

        Hi, ftMike.
        Thanks for your response.

        I renamed the constructor in both classes, but it's not working the way I
        expected.

        Now I have:
        Friend Class ValidateValue
        Private _child As ValidateValue
        ....
        Friend Sub init(ByVal validate As String)
        Dim compoundType As String
        Dim remainder As String
        Dim openParenPos As Integer
        Dim commaPos As Integer

        openParenPos = InStr(validate, "(")
        If openParenPos 0 Then
        compoundType = Mid(validate, 1, openParenPos - 1)
        remainder = Mid(validate, openParenPos + 1)
        remainder = Mid(remainder, 1, Len(remainder) - 1) ' strip closing paren
        Select Case compoundType
        Case "text", "textnum"
        _child = New ValidateValueTe xt
        _child.inittext (compoundType, remainder) ' this doesn't compile
        ....
        Friend Class ValidateValueTe xt
        Inherits ValidateValue

        Private _textMaxLen As Integer
        Private _textMinLen As Integer
        Private _validateType As validateTypes

        Friend Sub initText(ByVal compoundType As String, ByVal remainder As String)
        ....

        but the _child object in ValidateValue acts like a ValidateValue object in
        intellisense (the way it was declared,) not a ValidateValueTe xt object (the
        way it was instantiated.)

        So I have an 'is-a' relationship, like 'a dog is a mammal,' and I'm trying
        to figure out how to pass a mammalID to the Mammal class, which, if it's
        determined to be a dog, then creates an instance of a Dog object made
        available to the caller, along with setting the mammalType property to 'dog'.

        What I have is roughly equivalent to:
        Friend Class Mammal
        Private _child As Mammal
        ....
        Friend Sub init(ByVal mammalID As String)
        Dim compoundType As String
        Dim remainder As String
        Dim openParenPos As Integer
        Dim commaPos As Integer

        openParenPos = InStr(mammalID, "(")
        If openParenPos 0 Then
        compoundType = Mid(mammalID, 1, openParenPos - 1)
        remainder = Mid(mammalID, openParenPos + 1)
        remainder = Mid(remainder, 1, Len(remainder) - 1) ' strip closing paren
        Select Case compoundType
        Case "dog", "wolf"
        _child = New MammalDog
        _child.initDog( compoundType, remainder)
        ....
        Friend Class MammalDog
        Inherits Mammal

        Private _isWild as Boolean
        Private _mammalType As mammalTypes

        Friend Sub initDog(ByVal compoundType As String, ByVal remainder As String)
        ---
        _child.initDog( compoundType, remainder) won't compile, as it doesn't see
        initDog as a method of the _child object. It sees all the properties and
        methods of Mammal.

        What I'm trying to avoid is having something like:
        Friend Class Mammal
        Private _childDog As MammalDog
        Private _childCat As MammalCat

        but maybe that's what I need to do- have a member variable for each
        subclass, like with composition (has-a).

        I get the idea behind inheritance, but not how to actually implement it.

        Thanks again for the help,

        -Beth

        "Family Tree Mike" wrote:
        Well, is there a reason you don't want an empty constructor in
        ValidateValue? You don't necessarily have to call it. After that, it seems
        like you probably meant to have _textMaxLen, _textMinLen and _validateType
        be protected, not private.
        >
        "Beth" <Beth@discussio ns.microsoft.co mwrote in message
        news:05260BDC-07F9-41A4-A531-1CB242743D6B@mi crosoft.com...
        Hello.

        I'm trying to figure out how to create subclasses with properties specific
        to the subclass and so far it isn't going well.

        Right now I have a class with an enum representing the type. The class
        has
        all the properties specific to all the types, but what I want instead is
        to
        move those properties to subclasses specific to each type.

        I have code like this:

        Friend Class ValidateValue
        Private _textMaxLen As Integer
        Private _textMinLen As Integer
        Private _validateType As validateTypes

        Friend Sub New(ByVal validate As String)
        Dim compoundType As String
        Dim remainder As String
        Dim openParenPos As Integer
        Dim commaPos As Integer

        openParenPos = InStr(validate, "(")
        If openParenPos 0 Then
        compoundType = Mid(validate, 1, openParenPos - 1)
        remainder = Mid(validate, openParenPos + 1)
        remainder = Mid(remainder, 1, Len(remainder) - 1) ' strip closing paren
        Select Case compoundType
        Case "text", "textnum"
        If compoundType = "text" Then
        _validateType = validateTypes.t ext
        Else
        _validateType = validateTypes.t extNum
        End If
        commaPos = InStr(remainder , ",")
        If commaPos = 0 Then
        _textMaxLen = CInt(remainder)
        Else
        _textMaxLen = CInt(Mid(remain der, 1, commaPos - 1))
        _textMinLen = CInt(Mid(remain der, commaPos + 1))
        End If

        But since the maxLen and minLen properties are specific to the two text
        types, what I want to do is declare a subclass which inherits from the
        existing class and contains and sets the validateType, textMaxLen, and
        textMinLen properties given the compoundType and remainder.

        The problem I'm having is with the subclass's constructor. In the
        subclass,
        I want to pass the compoundType and remainder, and have code like:
        'Friend Class ValidateText
        ' Inherits ValidateValue

        ' Private _textMaxLen As Integer
        ' Private _textMinLen As Integer
        ' Private _validateType As validateTypes

        ' Friend Sub New(ByVal compoundType As String, ByVal remainder As String)
        ' Dim commaPos As Integer
        ' If compoundType = "text" Then
        ' _validateType = validateTypes.t ext
        ' Else
        ' _validateType = validateTypes.t extNum
        ' End If
        ' commaPos = InStr(remainder , ",")
        ' If commaPos = 0 Then
        ' _textMaxLen = CInt(remainder)
        ' Else
        ' _textMaxLen = CInt(Mid(remain der, 1, commaPos - 1))
        ' _textMinLen = CInt(Mid(remain der, commaPos + 1))
        ' End If
        ' End Sub

        But that doesn't work because the base class doesn't have a constructor
        without parameters. I want to use a parameter into a base class as a key
        to
        determine the subclass to create and then create one of my subclasses.

        I'm thinking in the base class I need a variable like:
        Private _child as ValidateValue

        And in the base class's constructor, have code like:
        Select Case compoundType
        Case "text", "textnum"
        _child = new ValidateText(co mpoundType, remainder)

        But I can't get the subclass to work.

        What should I be doing differently?

        Thanks for any help,

        -Beth

        Comment

        • =?Utf-8?B?QmV0aA==?=

          #5
          RE: subclassing

          Hi, OmegaSquared.
          Thanks for your response.

          My new properties only apply to the subclass, not the superclass or any
          other subclass.

          The superclass is passed a parameter it uses to determine which subclass to
          create, so I don't want the caller instantiating the inherited class. I want
          the caller instantiating the superclass with a subclassID and then getting
          the instance of the subclass from a property of the superclass (_child as
          superclass.)

          But I can't seem to get that to work, so for now I have all the properties
          specific to all the subclasses in the superclass.

          Thanks again for your help,

          -Beth


          "OmegaSquar ed" wrote:
          Hello, Beth,
          >
          You can call your base class's constructor (with an argument for the
          validate parameter) as the first executable line of the inherited classes
          constructor.
          >
          Also, as Mike says, you probably want the mentioned variables to be
          Protected (not private) and then remove the corresponding declarations from
          the inherited class.
          >
          Cheers,
          Randy
          >

          Comment

          • Tom Shelton

            #6
            Re: subclassing

            On 2008-11-10, OmegaSquared <OmegaSquared@d iscussions.micr osoft.comwrote:
            Hello, Beth,
            >
            You can call your base class's constructor (with an argument for the
            validate parameter) as the first executable line of the inherited classes
            constructor.
            >
            Also, as Mike says, you probably want the mentioned variables to be
            Protected (not private) and then remove the corresponding declarations from
            the inherited class.
            >
            Cheers,
            Randy
            >
            Minor nitpick - but, I have to disagree with the making the fields protected.
            I suggest one NEVER directly expose fields outside the class they are defined
            in.

            If you want subclasses to have access to a field in the base class, they you
            should provide that access as a Protected property rather then a protected
            field.

            If you think about it, the same reasons you never make fields public apply to
            making a field protected.

            --
            Tom Shelton

            Comment

            • =?Utf-8?B?RmFtaWx5IFRyZWUgTWlrZQ==?=

              #7
              Re: subclassing

              You are declaring _child as ValidateValue, but instantiating it as a
              ValidateValueTe xt. This can be fine, but, it really is a ValidateValue
              because of the declaration. This is why you get an error calling initText.

              In general, you should not try and do so much in the baseclass
              (ValidateValue) . Things specific to your sub class should be handled in the
              subclass (ValidateValueT ext).

              For example, back to your Mammal, Dog, Wolf, I have added Rhinocerous. I
              only place Wild as an attribute to the mammal class. Horns applies to
              relatively few mammals, and does not belong necessarily as part of the Mammal
              class. If there were sufficient horned animals you may want a HornedMammal
              class to derive from mammal. Hopefully this helps.


              Friend Class Mammal
              Protected Wild As Boolean
              End Class

              Friend Class Dog
              Inherits Mammal
              Public Sub New()
              Wild = False
              End Sub
              End Class

              Friend Class Wolf
              Inherits Mammal
              Public Sub New()
              Wild = True
              End Sub
              End Class

              Friend Class Rhinocerous
              Inherits Mammal
              Protected Horns As Integer
              Public Sub New()
              Wild = True
              Horns = 1
              End Sub
              End Class



              "Beth" wrote:
              Now I have:
              Friend Class ValidateValue
              Private _child As ValidateValue
              ...
              Friend Sub init(ByVal validate As String)
              Dim compoundType As String
              Dim remainder As String
              Dim openParenPos As Integer
              Dim commaPos As Integer
              Select Case compoundType
              Case "text", "textnum"
              _child = New ValidateValueTe xt
              _child.inittext (compoundType, remainder) ' this doesn't compile
              ...

              Comment

              • =?Utf-8?B?T21lZ2FTcXVhcmVk?=

                #8
                RE: subclassing

                Hi, Beth,

                OK, I think I understand now about your "new properties". So you should
                just remove these fields entirely from the base class. Also, Tom's point
                about making the fields private and exposing them via properties is more
                valid than just a "minor nitpick". (The only thing I might soften is the use
                of the word "NEVER". I rarely use such absolutes.)

                But I'm afraid that I'm not following what it is that you want to do. When
                you instantiate an object from the inherited class, the fields, properties
                and methods of the base class are also instantiated. If you instantiate an
                object from the base class, it will not have the attributes of a derived
                class.

                I suppose you could create some sort of sub-class "factory" within the base
                class, along the lines of the following. But it's not clear to me that this
                is what you are looking for.

                Cheers,
                Randy

                Public Class Form1
                Private Sub Button1_Click(B yVal sender As System.Object, ByVal e As
                System.EventArg s) Handles Button1.Click

                Dim SubObject1 As MyFirstInherite dClass
                SubObject1 =
                DirectCast(MyBa seClass.SubClas sCreator(MyBase Class.validateT ypes.text),
                MyFirstInherite dClass)
                MsgBox(SubObjec t1.WhatSortAmI)

                Dim SubObject2 As MySecondInherit edClass
                SubObject2 =
                DirectCast(MyBa seClass.SubClas sCreator(MyBase Class.validateT ypes.textnum),
                MySecondInherit edClass)
                MsgBox(SubObjec t2.WhatSortAmI)

                End Sub
                End Class

                Public Class MyFirstInherite dClass
                Inherits MyBaseClass

                Public Sub New()
                MyBase.New("I'm a ""text"" sort of object")
                End Sub

                End Class

                Public Class MySecondInherit edClass
                Inherits MyBaseClass

                Public Sub New()
                MyBase.New("I'm a ""textnum"" sort of object")
                End Sub

                End Class

                Public Class MyBaseClass

                Friend Enum validateTypes
                text
                textnum
                End Enum

                Private _validate As String

                Public Sub New(ByVal validate As String)
                _validate = validate
                End Sub

                Friend Shared Function SubClassCreator (ByVal SubClassType As
                validateTypes) As MyBaseClass
                Dim Result As MyBaseClass = Nothing
                Select Case SubClassType
                Case validateTypes.t ext
                Result = New MyFirstInherite dClass
                Case validateTypes.t extnum
                Result = New MySecondInherit edClass
                End Select
                Return Result
                End Function

                Friend ReadOnly Property WhatSortAmI() As String
                Get
                Return _validate
                End Get
                End Property
                End Class

                Comment

                • =?Utf-8?B?QmV0aA==?=

                  #9
                  Re: subclassing

                  Hi again, ftMike.

                  OK, let's say I have your classes below and a mammalID which is either 'D',
                  'W', or 'R'.
                  I want to pass the mammalID somewhere (maybe not to the base Mammal class,
                  but to some Mammal factory) and based on its value, create a more specific
                  mammal, such as a Dog.

                  The caller knows the mammalID and knows the result will be some kind of
                  mammal, just not which one. I was thinking I should pass the mammalID to the
                  Mammal's constructor, but maybe that factory function should be outsourced to
                  another class.

                  If it is outsourced to a MammalFactory, what would that class look like?

                  Here's what I don't want:
                  Friend Class MammalFactory
                  Private _dog as Dog
                  Private _wolf as Wolf
                  Private _rhino as Rhinocerous
                  Private _mammalType as Mammals

                  Enum Mammals
                  dog
                  wolf
                  rhino
                  End Enum

                  Friend Sub New (mammalID as string)
                  Select case mammalID
                  case 'D'
                  _dog = new Dog
                  _mammalType = dog
                  case 'W'
                  _wolf = new Wolf
                  _mammalType = wolf
                  case 'R'
                  _rhino = new Rhinocerous
                  _mammalType = rhino
                  End Select
                  End Sub

                  friend readonly property mammalType() as mammals
                  return _mammalType

                  Friend readonly property theDog() as Dog
                  return _dog

                  In other words, I'm trying to avoid having a property for each subclass, but
                  maybe that's the only way it will work.

                  The caller would have code like:
                  private sub makeMammal()
                  dim mammalID as string
                  dim theMammalFactor y as MammalFactory

                  mammalID = InputBox("What kind of mammal do you want? Enter D, W, or R.")
                  theMammalFactor y = new MammalFactory(m ammalID)
                  If theMammalFactor y.isWild then
                  Msgbox("Watch out! I made a wild animal.")
                  End if
                  select case theMammalFactor y.mammalType
                  case dog
                  dim myDog as Dog
                  myDog = theMammalFactor y.theDog
                  Msgbox("I made a dog! It can bark! Listen... " & myDog.bark)

                  I thought subclassing bought you some sort of convergence, but maybe that's
                  not at the implementation level, just at an interface level.

                  Thanks again for your response,

                  -Beth

                  "Family Tree Mike" wrote:
                  You are declaring _child as ValidateValue, but instantiating it as a
                  ValidateValueTe xt. This can be fine, but, it really is a ValidateValue
                  because of the declaration. This is why you get an error calling initText.
                  >
                  In general, you should not try and do so much in the baseclass
                  (ValidateValue) . Things specific to your sub class should be handled in the
                  subclass (ValidateValueT ext).
                  >
                  For example, back to your Mammal, Dog, Wolf, I have added Rhinocerous. I
                  only place Wild as an attribute to the mammal class. Horns applies to
                  relatively few mammals, and does not belong necessarily as part of the Mammal
                  class. If there were sufficient horned animals you may want a HornedMammal
                  class to derive from mammal. Hopefully this helps.
                  >
                  >
                  Friend Class Mammal
                  Protected Wild As Boolean
                  End Class
                  >
                  Friend Class Dog
                  Inherits Mammal
                  Public Sub New()
                  Wild = False
                  End Sub
                  End Class
                  >
                  Friend Class Wolf
                  Inherits Mammal
                  Public Sub New()
                  Wild = True
                  End Sub
                  End Class
                  >
                  Friend Class Rhinocerous
                  Inherits Mammal
                  Protected Horns As Integer
                  Public Sub New()
                  Wild = True
                  Horns = 1
                  End Sub
                  End Class
                  >
                  >
                  >
                  "Beth" wrote:
                  >
                  Now I have:
                  Friend Class ValidateValue
                  Private _child As ValidateValue
                  ...
                  Friend Sub init(ByVal validate As String)
                  Dim compoundType As String
                  Dim remainder As String
                  Dim openParenPos As Integer
                  Dim commaPos As Integer
                  >
                  Select Case compoundType
                  Case "text", "textnum"
                  _child = New ValidateValueTe xt
                  _child.inittext (compoundType, remainder) ' this doesn't compile
                  ...
                  >

                  Comment

                  • =?Utf-8?B?RmFtaWx5IFRyZWUgTWlrZQ==?=

                    #10
                    Re: subclassing

                    By the way, I agree with the other guys about the properties vs. attributes,
                    but will stick with what we have here.

                    I think to follow with your MammalFactory, I would write it like this:

                    Class MammalFactory
                    Shared Function CreateMammal(By Val mammalID As String) As Mammal
                    Select Case mammalID
                    Case "D"
                    Return New Dog
                    Case "W"
                    Return New Wolf
                    Case "R"
                    Return New Rhinocerous
                    End Select
                    Return Nothing
                    End Function
                    End Class


                    Then your caller might do:

                    Sub Main()
                    Dim fido As Mammal = MammalFactory.C reateMammal("W" )

                    If (TypeOf fido Is Dog) Then
                    Console.Out.Wri teLine("Doggie! ")
                    Else
                    Console.Out.Wri teLine("No doggie!")
                    End If

                    If (fido.Wild) Then
                    Console.Out.Wri teLine("Wild")
                    Else
                    Console.Out.Wri teLine("Crazy")
                    End If

                    Console.In.Read Line()
                    End Sub


                    "Beth" wrote:
                    Hi again, ftMike.
                    >
                    OK, let's say I have your classes below and a mammalID which is either 'D',
                    'W', or 'R'.
                    I want to pass the mammalID somewhere (maybe not to the base Mammal class,
                    but to some Mammal factory) and based on its value, create a more specific
                    mammal, such as a Dog.
                    >
                    The caller knows the mammalID and knows the result will be some kind of
                    mammal, just not which one. I was thinking I should pass the mammalID to the
                    Mammal's constructor, but maybe that factory function should be outsourced to
                    another class.
                    >
                    If it is outsourced to a MammalFactory, what would that class look like?
                    >
                    Here's what I don't want:
                    Friend Class MammalFactory
                    Private _dog as Dog
                    Private _wolf as Wolf
                    Private _rhino as Rhinocerous
                    Private _mammalType as Mammals
                    >
                    Enum Mammals
                    dog
                    wolf
                    rhino
                    End Enum
                    >
                    Friend Sub New (mammalID as string)
                    Select case mammalID
                    case 'D'
                    _dog = new Dog
                    _mammalType = dog
                    case 'W'
                    _wolf = new Wolf
                    _mammalType = wolf
                    case 'R'
                    _rhino = new Rhinocerous
                    _mammalType = rhino
                    End Select
                    End Sub
                    >
                    friend readonly property mammalType() as mammals
                    return _mammalType
                    >
                    Friend readonly property theDog() as Dog
                    return _dog
                    >
                    In other words, I'm trying to avoid having a property for each subclass, but
                    maybe that's the only way it will work.
                    >
                    The caller would have code like:
                    private sub makeMammal()
                    dim mammalID as string
                    dim theMammalFactor y as MammalFactory
                    >
                    mammalID = InputBox("What kind of mammal do you want? Enter D, W, or R.")
                    theMammalFactor y = new MammalFactory(m ammalID)
                    If theMammalFactor y.isWild then
                    Msgbox("Watch out! I made a wild animal.")
                    End if
                    select case theMammalFactor y.mammalType
                    case dog
                    dim myDog as Dog
                    myDog = theMammalFactor y.theDog
                    Msgbox("I made a dog! It can bark! Listen... " & myDog.bark)
                    >
                    I thought subclassing bought you some sort of convergence, but maybe that's
                    not at the implementation level, just at an interface level.
                    >
                    Thanks again for your response,
                    >
                    -Beth
                    >
                    "Family Tree Mike" wrote:
                    >
                    You are declaring _child as ValidateValue, but instantiating it as a
                    ValidateValueTe xt. This can be fine, but, it really is a ValidateValue
                    because of the declaration. This is why you get an error calling initText.

                    In general, you should not try and do so much in the baseclass
                    (ValidateValue) . Things specific to your sub class should be handled in the
                    subclass (ValidateValueT ext).

                    For example, back to your Mammal, Dog, Wolf, I have added Rhinocerous. I
                    only place Wild as an attribute to the mammal class. Horns applies to
                    relatively few mammals, and does not belong necessarily as part of the Mammal
                    class. If there were sufficient horned animals you may want a HornedMammal
                    class to derive from mammal. Hopefully this helps.


                    Friend Class Mammal
                    Protected Wild As Boolean
                    End Class

                    Friend Class Dog
                    Inherits Mammal
                    Public Sub New()
                    Wild = False
                    End Sub
                    End Class

                    Friend Class Wolf
                    Inherits Mammal
                    Public Sub New()
                    Wild = True
                    End Sub
                    End Class

                    Friend Class Rhinocerous
                    Inherits Mammal
                    Protected Horns As Integer
                    Public Sub New()
                    Wild = True
                    Horns = 1
                    End Sub
                    End Class



                    "Beth" wrote:
                    Now I have:
                    Friend Class ValidateValue
                    Private _child As ValidateValue
                    ...
                    Friend Sub init(ByVal validate As String)
                    Dim compoundType As String
                    Dim remainder As String
                    Dim openParenPos As Integer
                    Dim commaPos As Integer
                    Select Case compoundType
                    Case "text", "textnum"
                    _child = New ValidateValueTe xt
                    _child.inittext (compoundType, remainder) ' this doesn't compile
                    ...

                    Comment

                    • =?Utf-8?B?QmV0aA==?=

                      #11
                      RE: subclassing

                      Hi, again, Omega.

                      I'll try explaining what I'm trying to do another way.

                      Let's say at runtime, the user wants to edit a value and I've looked in the
                      database and determined how to validate the value they want to edit. A value
                      might be displayed and validated as a text field limited to numeric entry
                      with a minimum length of 1 and a maximum length of 15 characters, for
                      example. In this case, the validation string is 'textnum(1,15)'

                      I'm doing the string parsing in my existing ValidateValue class, except it
                      includes properties like textMinLen and textMaxLen which I'd prefer to move
                      (as you suggest) to a ValidateValueTe xt class, because those properties only
                      apply to text values, not combo box or memo values.

                      So given a validation string, I can determine which subclass I need to
                      create, and would like to create it passing the additional details it needs
                      to set its own properties.

                      Then I need the caller to get a reference to the newly instantiated subclass
                      through a property of its instance of the base class.

                      And I'm not sure how to do that without creating properties for each of my
                      subclasses.

                      It's similar to your Function SubClassCreator , which returns a value of the
                      base class type, not of a specific subclass, except that the caller doesn't
                      know which subclass to create. The base class does after it parses the
                      validation string.

                      I thought I could declare a variable of the base class type and assign it to
                      a new instance of a subclass and get to the subclass's methods, but it
                      doesn't work that way.

                      Sorry if this is confusing, but I need to create an instance of the base
                      class first, which then can determine which subclass to create and then
                      create it so it can be referenced by the caller.

                      Or maybe this is just a poor use of subclassing and I should keep it the way
                      I have it, I don't know.

                      Thanks again for your help,

                      -Beth

                      "OmegaSquar ed" wrote:
                      Hi, Beth,
                      >
                      OK, I think I understand now about your "new properties". So you should
                      just remove these fields entirely from the base class. Also, Tom's point
                      about making the fields private and exposing them via properties is more
                      valid than just a "minor nitpick". (The only thing I might soften is the use
                      of the word "NEVER". I rarely use such absolutes.)
                      >
                      But I'm afraid that I'm not following what it is that you want to do. When
                      you instantiate an object from the inherited class, the fields, properties
                      and methods of the base class are also instantiated. If you instantiate an
                      object from the base class, it will not have the attributes of a derived
                      class.
                      >
                      I suppose you could create some sort of sub-class "factory" within the base
                      class, along the lines of the following. But it's not clear to me that this
                      is what you are looking for.
                      >
                      Cheers,
                      Randy
                      >
                      Public Class Form1
                      Private Sub Button1_Click(B yVal sender As System.Object, ByVal e As
                      System.EventArg s) Handles Button1.Click
                      >
                      Dim SubObject1 As MyFirstInherite dClass
                      SubObject1 =
                      DirectCast(MyBa seClass.SubClas sCreator(MyBase Class.validateT ypes.text),
                      MyFirstInherite dClass)
                      MsgBox(SubObjec t1.WhatSortAmI)
                      >
                      Dim SubObject2 As MySecondInherit edClass
                      SubObject2 =
                      DirectCast(MyBa seClass.SubClas sCreator(MyBase Class.validateT ypes.textnum),
                      MySecondInherit edClass)
                      MsgBox(SubObjec t2.WhatSortAmI)
                      >
                      End Sub
                      End Class
                      >
                      Public Class MyFirstInherite dClass
                      Inherits MyBaseClass
                      >
                      Public Sub New()
                      MyBase.New("I'm a ""text"" sort of object")
                      End Sub
                      >
                      End Class
                      >
                      Public Class MySecondInherit edClass
                      Inherits MyBaseClass
                      >
                      Public Sub New()
                      MyBase.New("I'm a ""textnum"" sort of object")
                      End Sub
                      >
                      End Class
                      >
                      Public Class MyBaseClass
                      >
                      Friend Enum validateTypes
                      text
                      textnum
                      End Enum
                      >
                      Private _validate As String
                      >
                      Public Sub New(ByVal validate As String)
                      _validate = validate
                      End Sub
                      >
                      Friend Shared Function SubClassCreator (ByVal SubClassType As
                      validateTypes) As MyBaseClass
                      Dim Result As MyBaseClass = Nothing
                      Select Case SubClassType
                      Case validateTypes.t ext
                      Result = New MyFirstInherite dClass
                      Case validateTypes.t extnum
                      Result = New MySecondInherit edClass
                      End Select
                      Return Result
                      End Function
                      >
                      Friend ReadOnly Property WhatSortAmI() As String
                      Get
                      Return _validate
                      End Get
                      End Property
                      End Class
                      >

                      Comment

                      • =?Utf-8?B?QmV0aA==?=

                        #12
                        Re: subclassing

                        I think I got it.

                        I need a module-level variable declared as the base class type exposed
                        through a property, like this:
                        Friend Class ValidateValue
                        Private _child As ValidateValue

                        Friend ReadOnly Property child() As ValidateValue
                        Return _child

                        but once I know which subclass to create, I need to declare another variable
                        of the subclass type, set its properties, and then set that subclass variable
                        to my module-level base class variable, like:

                        Select Case compoundType
                        Case "text", "textnum"
                        Dim childText As ValidateValueTe xt
                        childText = New ValidateValueTe xt
                        childText.initT ext(compoundTyp e, remainder) ' sets validateValue to
                        text or textnum
                        _child = childText

                        Then the caller can access the base class's child property and get an object
                        of whichever subclass is appropriate, and convert it explicitly to the
                        correct subclass based on the validateType set in the subclass.

                        So I think I need to change
                        Private _validateType As validateTypes
                        in the base class to protected, or something.

                        I can work with that some more- at least the thing compiles now!

                        Thanks again for the help,

                        -Beth

                        "Family Tree Mike" wrote:
                        By the way, I agree with the other guys about the properties vs. attributes,
                        but will stick with what we have here.
                        >
                        I think to follow with your MammalFactory, I would write it like this:
                        >
                        Class MammalFactory
                        Shared Function CreateMammal(By Val mammalID As String) As Mammal
                        Select Case mammalID
                        Case "D"
                        Return New Dog
                        Case "W"
                        Return New Wolf
                        Case "R"
                        Return New Rhinocerous
                        End Select
                        Return Nothing
                        End Function
                        End Class
                        >
                        >
                        Then your caller might do:
                        >
                        Sub Main()
                        Dim fido As Mammal = MammalFactory.C reateMammal("W" )
                        >
                        If (TypeOf fido Is Dog) Then
                        Console.Out.Wri teLine("Doggie! ")
                        Else
                        Console.Out.Wri teLine("No doggie!")
                        End If
                        >
                        If (fido.Wild) Then
                        Console.Out.Wri teLine("Wild")
                        Else
                        Console.Out.Wri teLine("Crazy")
                        End If
                        >
                        Console.In.Read Line()
                        End Sub
                        >
                        >
                        "Beth" wrote:
                        >
                        Hi again, ftMike.

                        OK, let's say I have your classes below and a mammalID which is either 'D',
                        'W', or 'R'.
                        I want to pass the mammalID somewhere (maybe not to the base Mammal class,
                        but to some Mammal factory) and based on its value, create a more specific
                        mammal, such as a Dog.

                        The caller knows the mammalID and knows the result will be some kind of
                        mammal, just not which one. I was thinking I should pass the mammalID to the
                        Mammal's constructor, but maybe that factory function should be outsourced to
                        another class.

                        If it is outsourced to a MammalFactory, what would that class look like?

                        Here's what I don't want:
                        Friend Class MammalFactory
                        Private _dog as Dog
                        Private _wolf as Wolf
                        Private _rhino as Rhinocerous
                        Private _mammalType as Mammals

                        Enum Mammals
                        dog
                        wolf
                        rhino
                        End Enum

                        Friend Sub New (mammalID as string)
                        Select case mammalID
                        case 'D'
                        _dog = new Dog
                        _mammalType = dog
                        case 'W'
                        _wolf = new Wolf
                        _mammalType = wolf
                        case 'R'
                        _rhino = new Rhinocerous
                        _mammalType = rhino
                        End Select
                        End Sub

                        friend readonly property mammalType() as mammals
                        return _mammalType

                        Friend readonly property theDog() as Dog
                        return _dog

                        In other words, I'm trying to avoid having a property for each subclass, but
                        maybe that's the only way it will work.

                        The caller would have code like:
                        private sub makeMammal()
                        dim mammalID as string
                        dim theMammalFactor y as MammalFactory

                        mammalID = InputBox("What kind of mammal do you want? Enter D, W, or R.")
                        theMammalFactor y = new MammalFactory(m ammalID)
                        If theMammalFactor y.isWild then
                        Msgbox("Watch out! I made a wild animal.")
                        End if
                        select case theMammalFactor y.mammalType
                        case dog
                        dim myDog as Dog
                        myDog = theMammalFactor y.theDog
                        Msgbox("I made a dog! It can bark! Listen... " & myDog.bark)

                        I thought subclassing bought you some sort of convergence, but maybe that's
                        not at the implementation level, just at an interface level.

                        Thanks again for your response,

                        -Beth

                        "Family Tree Mike" wrote:
                        You are declaring _child as ValidateValue, but instantiating it as a
                        ValidateValueTe xt. This can be fine, but, it really is a ValidateValue
                        because of the declaration. This is why you get an error calling initText.
                        >
                        In general, you should not try and do so much in the baseclass
                        (ValidateValue) . Things specific to your sub class should be handled in the
                        subclass (ValidateValueT ext).
                        >
                        For example, back to your Mammal, Dog, Wolf, I have added Rhinocerous. I
                        only place Wild as an attribute to the mammal class. Horns applies to
                        relatively few mammals, and does not belong necessarily as part of the Mammal
                        class. If there were sufficient horned animals you may want a HornedMammal
                        class to derive from mammal. Hopefully this helps.
                        >
                        >
                        Friend Class Mammal
                        Protected Wild As Boolean
                        End Class
                        >
                        Friend Class Dog
                        Inherits Mammal
                        Public Sub New()
                        Wild = False
                        End Sub
                        End Class
                        >
                        Friend Class Wolf
                        Inherits Mammal
                        Public Sub New()
                        Wild = True
                        End Sub
                        End Class
                        >
                        Friend Class Rhinocerous
                        Inherits Mammal
                        Protected Horns As Integer
                        Public Sub New()
                        Wild = True
                        Horns = 1
                        End Sub
                        End Class
                        >
                        >
                        >
                        "Beth" wrote:
                        >
                        Now I have:
                        Friend Class ValidateValue
                        Private _child As ValidateValue
                        ...
                        Friend Sub init(ByVal validate As String)
                        Dim compoundType As String
                        Dim remainder As String
                        Dim openParenPos As Integer
                        Dim commaPos As Integer
                        >
                        Select Case compoundType
                        Case "text", "textnum"
                        _child = New ValidateValueTe xt
                        _child.inittext (compoundType, remainder) ' this doesn't compile
                        ...
                        >

                        Comment

                        • =?Utf-8?B?T21lZ2FTcXVhcmVk?=

                          #13
                          RE: subclassing

                          Hello, Beth,

                          Is the following possibly the sort of thing that you are trying to do?

                          Public Class Form1

                          Private Sub Button2_Click(B yVal sender As System.Object, ByVal e As
                          System.EventArg s) Handles Button2.Click

                          Dim validate As String = "textnum(1, 15)" ' validate would come
                          from DB in real application.
                          Dim NewObject1 As MyBaseClass = MyBaseClass.Sub ClassCreator(va lidate)
                          Dim EntryOK As Boolean = NewObject1.Vali dEntry("some text entry")

                          validate = "text(1,15) " ' validate would come from DB in real
                          application.
                          Dim NewObject2 As MyBaseClass = MyBaseClass.Sub ClassCreator(va lidate)
                          EntryOK = NewObject2.Vali dEntry("some text entry")

                          End Sub
                          End Class

                          Public Class MyBaseClass

                          Private _validate As String

                          Public Sub New(ByVal validate As String)

                          _validate = validate

                          End Sub

                          Friend Shared Function SubClassCreator (ByVal validate As String) As
                          MyBaseClass

                          Dim validateType As String = validate.Split( "("c)(0)
                          Dim Result As MyBaseClass = Nothing
                          Select Case validateType
                          Case "text"
                          Result = New MyFirstInherite dClass
                          Case "textnum"
                          Result = New MySecondInherit edClass
                          End Select
                          Return Result

                          End Function

                          Friend Overridable ReadOnly Property ValidEntry(ByVa l Entry As String)
                          As Boolean
                          Get
                          MsgBox(Entry & " is being validated by MyBaseClass.")
                          End Get
                          End Property
                          End Class

                          Public Class MyFirstInherite dClass

                          Inherits MyBaseClass

                          Public Sub New()
                          MyBase.New("I'm a ""text"" sort of object")
                          End Sub

                          Friend Overrides ReadOnly Property ValidEntry(ByVa l Entry As String) As
                          Boolean
                          Get
                          MsgBox(Entry & " is being validated by the
                          MyFirstInherite dClass.")
                          End Get
                          End Property

                          End Class

                          Public Class MySecondInherit edClass

                          Inherits MyBaseClass

                          Public Sub New()
                          MyBase.New("I'm a ""textnum"" sort of object")
                          End Sub

                          Friend Overrides ReadOnly Property ValidEntry(ByVa l Entry As String) As
                          Boolean
                          Get
                          MsgBox(Entry & " is being validated by the
                          MySecondInherit edClass.")
                          End Get
                          End Property

                          End Class

                          Comment

                          • =?Utf-8?B?QmV0aA==?=

                            #14
                            RE: subclassing

                            Hi again, Omega.

                            The problem is the form doesn't know which subclass to create, it just has a
                            key that's used to look up the validate string in the db.

                            So I need to use the key to look up the validate string and pass it to the
                            subClassCreator , declared as the superclass, and then based on the
                            superclass.vali dateType property (either enum text, textnum, etc.) create an
                            instance of the text/grid/cbo subclass, if it's appropriate (memo types don't
                            have a subclass.)

                            The thing I was missing was I needed a module-level variable declared as the
                            superclass, then after parsing the string to determine the type (I'll look
                            into the .split method, thanks,) declare and create a new instance of the
                            subclass, then assign that new subclass instance to the module-level
                            superclass variable, exposed as a property to the caller (an edit form).

                            The form actually does the validation, but the subclass provides the details
                            of how the caller should do the validation.

                            Here's some of the code:
                            Public Class frmEdit
                            Private _validate As ValidateValue
                            Private _validateChild As ValidateValue
                            Private _validateType As ValidateValue.v alidateTypes

                            Friend Sub init(<params>)
                            <create displaySet>
                            _displaySetCol = displaySet.disp laySetCol(ordin alPos) ' ordinalPos is
                            an input param
                            _isNothing = (_displaySetCol .validation Is Nothing)
                            If _isNothing Then
                            Exit Sub ' not everything can be edited
                            Else
                            _validate = _displaySetCol. validation
                            End If
                            _validateType = _validate.valid ateType
                            txtValue.Visibl e = (_validateType = ValidateValue.v alidateTypes.te xt) Or
                            (_validateType = ValidateValue.v alidateTypes.da teTime) Or
                            (_validateType = ValidateValue.v alidateTypes.te xtNum)
                            txtValueMultili ne.Visible = (_validateType =
                            ValidateValue.v alidateTypes.me mo)
                            cboValue.Visibl e = (_validateType = ValidateValue.v alidateTypes.cb o)
                            dgvValue.Visibl e = (_validateType = ValidateValue.v alidateTypes.gr id)

                            validationMsg = ""
                            _validateChild = _validate.child
                            Select Case _validateType
                            Case ValidateValue.v alidateTypes.te xt,
                            ValidateValue.v alidateTypes.te xtNum
                            Dim valText As ValidateValueTe xt
                            valText = _validateChild
                            txtValue.Text = value ' input param
                            txtValue.MaxLen gth = valText.textMax Len
                            If _validateType = ValidateValue.v alidateTypes.te xtNum Then
                            validationMsg = "Enter a number."
                            ElseIf valText.textMin Len 0 Then
                            validationMsg = "Enter at least " & valText.textMin Len & "
                            character(s)."
                            Else
                            validationMsg = ""
                            End If

                            Friend Class ValidateValue
                            ' functions specific to validate column of one row of displaySetColum n table
                            Private _child As ValidateValue
                            Private _validateType As validateTypes

                            Friend Enum validateTypes
                            text
                            textNum
                            dateTime
                            memo
                            cbo
                            grid
                            End Enum

                            Friend Sub init(ByVal validate As String)
                            Dim compoundType As String
                            Dim remainder As String
                            Dim openParenPos As Integer

                            openParenPos = InStr(validate, "(")
                            If openParenPos 0 Then
                            compoundType = Mid(validate, 1, openParenPos - 1)
                            remainder = Mid(validate, openParenPos + 1)
                            remainder = Mid(remainder, 1, Len(remainder) - 1) ' strip closing
                            paren
                            Select Case compoundType
                            Case "text", "textnum"
                            Dim childText As ValidateValueTe xt
                            childText = New ValidateValueTe xt
                            childText.initT ext(compoundTyp e, remainder)
                            _validateType = childText.valid ateType
                            _child = childText ' this is the piece I was missing. I
                            thought childText should be declared as the supertype


                            Friend ReadOnly Property child() As ValidateValue
                            Get
                            Return _child
                            End Get
                            End Property

                            Friend ReadOnly Property validateType() As validateTypes
                            Get
                            Return _validateType
                            End Get
                            End Property

                            Friend Class ValidateValueTe xt
                            Inherits ValidateValue

                            Private _textMaxLen As Integer
                            Private _textMinLen As Integer
                            Private _validateType As validateTypes

                            Friend Sub initText(ByVal compoundType As String, ByVal remainder As String)
                            Dim commaPos As Integer
                            If compoundType = "text" Then
                            _validateType = validateTypes.t ext
                            Else
                            _validateType = validateTypes.t extNum
                            End If
                            commaPos = InStr(remainder , ",")
                            If commaPos = 0 Then
                            _textMaxLen = CInt(remainder)
                            Else
                            _textMaxLen = CInt(Mid(remain der, 1, commaPos - 1))
                            _textMinLen = CInt(Mid(remain der, commaPos + 1))
                            End If
                            End Sub

                            Friend Overloads ReadOnly Property validateType() As validateTypes
                            Get
                            Return _validateType
                            End Get
                            End Property

                            Friend ReadOnly Property textMaxLen() As Integer
                            Get
                            Return _textMaxLen
                            End Get
                            End Property

                            Friend ReadOnly Property textMinLen() As Integer
                            Get
                            Return _textMinLen
                            End Get
                            End Property

                            I didn't really understand how to implement subclassing, I just knew that's
                            what I 'should' be doing.

                            Thanks again for your responses. Trying to crawl around in someone else's
                            head can be a pain.

                            -Beth

                            "OmegaSquar ed" wrote:
                            Hello, Beth,
                            >
                            Is the following possibly the sort of thing that you are trying to do?
                            >
                            Public Class Form1
                            >
                            Private Sub Button2_Click(B yVal sender As System.Object, ByVal e As
                            System.EventArg s) Handles Button2.Click
                            >
                            Dim validate As String = "textnum(1, 15)" ' validate would come
                            from DB in real application.
                            Dim NewObject1 As MyBaseClass = MyBaseClass.Sub ClassCreator(va lidate)
                            Dim EntryOK As Boolean = NewObject1.Vali dEntry("some text entry")
                            >
                            validate = "text(1,15) " ' validate would come from DB in real
                            application.
                            Dim NewObject2 As MyBaseClass = MyBaseClass.Sub ClassCreator(va lidate)
                            EntryOK = NewObject2.Vali dEntry("some text entry")
                            >
                            End Sub
                            End Class

                            Comment

                            Working...