Polymorphism

  • Thread starter Richard Tappenden
  • Start date
R

Richard Tappenden

Hi!

I'm struggling a bit with Polymorphism in vb.net. There is something I know
I can do in C++, but I cannot seem to do it in vb.net (or c# for that
matter).

Basically, I have an abstract base class that deals with adding, deleting,
editing another class.

I have written an implementation of that class, and also a derived version
of the 'managed' class - so effectively my derived version manages a
specialised version of whatever the base one does. However, the compiler
complains that I havent implemented the MustInherit methods...

To explain a bit better...


Public Class CMessage
' This is the "managed" class

Public MustInherit Class CMessageManager
' This is the abstract base class
Public MustOverride Function MessageReceived (ByRef objMessage As
CMessage) As Boolean

Public Class CEmail Inherits CMessage
' Derived version

Public Class CEmailMessageManager Inherits CMessageManager
' Implemented version - want it to deal with emails

Public MustOverride Function MessageReceived (ByRef objMessage As CEmail)
As Boolean
' Pass in an email and deal with it


This concept is supported by C++ - it must be possible to do it in .NET, but
I really dont know how.

Any help would be greatly appreciated!
 
T

Tom Shelton

Hi!

I'm struggling a bit with Polymorphism in vb.net. There is something I know
I can do in C++, but I cannot seem to do it in vb.net (or c# for that
matter).

Basically, I have an abstract base class that deals with adding, deleting,
editing another class.

I have written an implementation of that class, and also a derived version
of the 'managed' class - so effectively my derived version manages a
specialised version of whatever the base one does. However, the compiler
complains that I havent implemented the MustInherit methods...

To explain a bit better...


Public Class CMessage
' This is the "managed" class

Public MustInherit Class CMessageManager
' This is the abstract base class
Public MustOverride Function MessageReceived (ByRef objMessage As
CMessage) As Boolean

Public Class CEmail Inherits CMessage
' Derived version

Public Class CEmailMessageManager Inherits CMessageManager
' Implemented version - want it to deal with emails

Public MustOverride Function MessageReceived (ByRef objMessage As CEmail)
As Boolean
' Pass in an email and deal with it


This concept is supported by C++ - it must be possible to do it in .NET, but
I really dont know how.

Any help would be greatly appreciated!

I'm not sure what the problem is - the compiler is telling you exactly
what the problem is... If you want to be able to use
CEmailMessageManager then you must override the MessageReceived
function..

Public Class CEmailMessageManager Inherits CMessageManager

Public Overrides Function MessageReceived (ByRef objMessage As
CEmail) As Boolean
' Do stuff
End Function
End Class

Even in C++ this is the rule. You can't use a function that has no
implementation. The rules for using Abstract base classes are pretty
much the same in VB.NET as the are in C++.
 
R

Richard Tappenden

Hi Tom,

Thanks for the reply - but I think you've misunderstood the question - I'm
well aware that I can create an instance of an abstract class etc...

The problem is that I cant seem to override the base class methods unless
they all use the base message class to do the operations - i.e:

The base class method =
Public MustOverride Function MessageReceived (ByRef objMessage As CMessage)
As Boolean

My derived version
Public Overrides Function MessageReceived(ByRef objMessage As CEmailMessage)
As Boolean
' Do something
End Function.

The overridden version complains - stating that I still need to override
MessageReceived(ByRef objMessage CMessage) As Boolean.

In C++, you can do this - i.e. it resolves the virtual table correctly.

For example - check these c++ files...(apologies if they don't look nice, I
knocked them up quickly to prove the point)



 
A

Armin Zingler

Richard Tappenden said:
The problem is that I cant seem to override the base class methods
unless they all use the base message class to do the operations -
i.e:

The base class method =
Public MustOverride Function MessageReceived (ByRef objMessage As
CMessage) As Boolean

My derived version
Public Overrides Function MessageReceived(ByRef objMessage As
CEmailMessage) As Boolean
' Do something
End Function.

The overridden version complains - stating that I still need to
override MessageReceived(ByRef objMessage CMessage) As Boolean.

The derived class must contain a procedure with the same signature. In your
case, the signature is different because the type of the argument is
CEmailMessage, not CMessage as in the base class.
 
T

Tom Shelton

Hi Tom,

Thanks for the reply - but I think you've misunderstood the question - I'm
well aware that I can create an instance of an abstract class etc...

The problem is that I cant seem to override the base class methods unless
they all use the base message class to do the operations - i.e:

The base class method =
Public MustOverride Function MessageReceived (ByRef objMessage As CMessage)
As Boolean

My derived version
Public Overrides Function MessageReceived(ByRef objMessage As CEmailMessage)
As Boolean
' Do something
End Function.

The overridden version complains - stating that I still need to override
MessageReceived(ByRef objMessage CMessage) As Boolean.

Aah, now I understand and Armin hit the nail on the head. You have not
overridden the base function because the sig does not match. You are
passing a CEmailMessage - not CMessage, which is what the base class
defines.
 
R

Richard Tappenden

Hi Armin.

Thanks for the reply - I understand what you are saying, however the
CEmailMessage class is derived from CMessage - so it should work (at least
it does work that way in C++)
 
A

Armin Zingler

Richard Tappenden said:
Thanks for the reply - I understand what you are saying, however
the CEmailMessage class is derived from CMessage - so it should work
(at least it does work that way in C++)

In .NET, the signatures must match exactly. I haven't thought about why they
have to (yet).
 
J

Jay B. Harlow [MVP - Outlook]

Richard,
..NET is not C++! Remember C++ also supports Multiple Inheritance where as
..NET does not.

C++ allows for covariant parameters, however .NET (the CLR itself) does not
allow for covariant parameters.

I understand that you can use Eiffel for .NET http://www.eiffel.com/ and
have covariant parameters, however you will not be able to use that code
with C# or VB.NET, as it is not CLS complient...

Hope this helps
Jay

Richard Tappenden said:
Hi Armin.

Thanks for the reply - I understand what you are saying, however the
CEmailMessage class is derived from CMessage - so it should work (at least
it does work that way in C++)
<<snip>>
 
A

Armin Zingler

Armin Zingler said:
In .NET, the signatures must match exactly. I haven't thought about
why they have to (yet).

Now I did. ;-)

If I am the author of the base class, I want to force the author(s) of the
derived class(es) to accept *any* CMessage object. If you change the
signature to CEMailMessage, you break this enforcement because not any
CMessage object can be passed anymore.
 
R

Richard Tappenden

That really defeats the point of OO programming - remember the CEmailMessage
is "a kind of" CMessage object - therefore I should be able to pass it into
the base class method - and it will do anything with it that it could with a
CMessage.

If I then implement a more complete, specific kind of message object and a
manager class that deals with them as well - it should be able to take
advantage of the new improved class, and yet still be "a kind of" base
object.

I must say, I'm pretty disappointed that this hasn't been put into .NET, and
I really think it will make a few things difficult when moving code over
from C++ to C#.

Incidently, in C++ I think you can enforce types by using the Explicit
keyword, which would restrict the types as per your idea below.
 
A

Armin Zingler

Richard Tappenden said:
That really defeats the point of OO programming - remember the
CEmailMessage is "a kind of" CMessage object - therefore I should be
able to pass it into the base class method - and it will do anything
with it that it could with a CMessage.

CEMailMessage is a kind of CMessage object, but not every CMessage object is
a CEMailMessage object.

Imagine, you derive another class from CMessage:

class CNewsMessage
inherits CMessage
end class

The author of the base class wants that *any* kind of CMessage
object can be passed to the procedure. If you change the signature to
CEMailMessage, a CNewsMessage object can *not* be passed - although it *is*
a kind of CMessage object. This would brake the rule defined in the base
class.
 
R

Richard Tappenden

Sorry Armin, I dont think you quite understand the concept...

The base class would take any kind (lets pretend has been implemented...)

If someone writes a specialised version of that base class, they are more
than entitled to state that the method requires a specialised version of the
parameter (especially seeing as they could be several levels up in the
heirarchy).

The derived one could still pass the method down to the base implementation,
because anything you could do with the base one, you can do with the derived
one (because we are talking object oriented programming). The derived one
could then perform any additional or different processing with the more
advanced one.

It should be down to the derived class to decide whether it wants to use a
derived version or not - the base class should not specify this.

So in your example, a CEmailManager would only want CEmailMessages - it wont
accept CNewsMessage. Another class would have to be written (CNewsManager)
to explicitly deal with news messages, because they have to have slightly
different code inside (for example in an email you might want to filter its
content for spam, but a news message you might not want to).

Any filtering/processing that could be done on a CMessage could be written
in the base class, so...

CMessageManager -
Sub MessageReceived(msg As CMessage)
' Do sommat
End Sub

CEMailManager
Sub MessageReceived(msg As CEmailMessage)
MyBase.MessageReceived(msg)
FilterForSpam(msg)
End Sub

CNewsManager
Sub MessageReceived(msg As CNewsMessage)
MyBase.MessageReceived(msg)
AcceptMessage(msg)
End Sub
 
A

Armin Zingler

Richard Tappenden said:
Sorry Armin, I dont think you quite understand the concept...

I think *you* don't understand it - but don't let us start this...
The base class would take any kind (lets pretend has been
implemented...)

If someone writes a specialised version of that base class, they are
more than entitled to state that the method requires a specialised
version of the parameter (especially seeing as they could be several
levels up in the heirarchy).

Yes, you can add overloaded versions, but you still have to implement the
version with the same signature as in the base class - it is declared as
MustOverride.
The derived one could still pass the method down to the base
implementation, because anything you could do with the base one, you
can do with the derived one (because we are talking object oriented
programming). The derived one could then perform any additional or
different processing with the more advanced one.

It should be down to the derived class to decide whether it wants to
use a derived version or not - the base class should not specify
this.

Yes again, the derived classes might have overloaded versions that accept
specialized (=derived) objects. Even if you don't add overloaded versions,
you can pass objects derived from the base class. That's called
"polymorphism" as mentioned in the subject.
So in your example, a CEmailManager would only want CEmailMessages -
it wont accept CNewsMessage. Another class would have to be written
(CNewsManager) to explicitly deal with news messages, because they
have to have slightly different code inside (for example in an email
you might want to filter its content for spam, but a news message you
might not want to).

Any filtering/processing that could be done on a CMessage could be
written in the base class, so...

CMessageManager -
Sub MessageReceived(msg As CMessage)
' Do sommat
End Sub

CEMailManager
Sub MessageReceived(msg As CEmailMessage)
MyBase.MessageReceived(msg)
FilterForSpam(msg)
End Sub

CNewsManager
Sub MessageReceived(msg As CNewsMessage)
MyBase.MessageReceived(msg)
AcceptMessage(msg)
End Sub

This example shows the right usage of polymorphism: You can pass a CMessage
object or any object derived from CMessage to
CMessageManager.MessageReceived. As the method is not declared as
MustOverride, you are not forced to override it in the derived classes.

Further more, I can only repeat myself: As the method in CMessageManager is
declared as MustOverride, you must override it in the derived class. The
base class' author wants the author of the derived class
to write a method that accepts *any* type of CMessage object. What does
"any" mean? It means that the type of the passed object can be CMessage or
derived from CMessage. Now, if you would limit it to CEmailMessage objects,
you can not pass a CNewsMessage object. But why? CNewsMessage is derived
from CMessage, so it must work. Consequently you can not create this
limitation.
 
J

Jay B. Harlow [MVP - Outlook]

Richard,
That really defeats the point of OO programming -
Some would say that not supporting Multiple Inheritance would also defeat
the point of OO programming... ;-) But as Armin stated, lets not go there!
;-)

I'm really not sure why .NET does not support Covariant return types &
parameters. I find them useful in some cases. There was a discussion about
this a year and a half to two years ago, where someone pointed to a web site
about why covariant return types & parameters "don't work" however I do not
have that link handy.
I must say, I'm pretty disappointed that this hasn't been put into .NET, and
I really think it will make a few things difficult when moving code over
from C++ to C#.
Rather then moving to C#, have you considered Managed C++? I have not used
Managed C++ enough to know if it preserved covariant return types &
parameters or not (for managed classes). I understand that Eiffel .NET
supports them. Just be aware there are .NET languages that support covariant
return types & parameters, however they are not required to interop with
other languages...

Hope this helps
Jay
 
R

Richard Tappenden

Hi Jay,

Funnily enough, I dont miss multiple inheritance much :)

I have used it in a few cases, but only because we were to lazy to
encapsulate the second class that it derived from - tbh multiple inheritance
is a very powerful tool, but it requires a very thorough design. Bad
implementation of this causes serious problems.

However, I think with what I am requesting, it can actually really help the
structure of the software - especially if you are creating a heirarchical,
easily deployable and updatable solution.

Still, never mind. I'll put the base types in the prototypes, and case them
to the ones I require.
 
J

Jay B. Harlow [MVP - Outlook]

Armin & Richard,
I think *you* don't understand it - but don't let us start this...

This reminds me of the story of three blind men who stumble upon an elephant
and are attempting to describe it... ;-) I get the impression all three of
use understand, we are just describing a different part of the same animal!

Armin: You do realize that Richard is referring to Covariant return types &
parameters, which is an advanced OO technique that simple is not available
on .NET? Although I think you're close to why it doesn't always work in
practice, or why it doesn't always work as you would expect.

Personally Covariant return types & parameters are similar to Multiple
Inheritance. They are not available in .NET, I can live with that. It would
be nice, in some cases if they were available, but they are not, life goes
on. The only real workaround, that I know of, is as Armin & I suggested
overloads and/or runtime type checking.

This is similar to Generics: today they are not available, however with
Whidbey they will be available.

Maybe if enough people submit a MS Wish then in .NET 3.0 or 4.0 we may get
covariant return types & parameters. Of course MS may have really good
technical reasons on why they are not supported, unfortunately I do not know
what those technical reasons are. I do know that it will make the work of
the JIT a little more challenging. ;-) Either way I understand that Eiffel
..NET supports both MI & Covariants today, if you are willing to stay within
Eiffel .NET.

Richard: Have you considered submitting a request to MS Wish, requesting
that Covariant return types & parameters be supported in .NET?
http://register.microsoft.com/mswish/suggestion.asp

Hope this helps
Jay
 
A

Armin Zingler

Jay B. Harlow said:
I do
know that it will make the work of the JIT a little more challenging.
;-)

Hehe :)

(my only contribution as my knowledge is exhausted in this case :) )
 
R

Richard Tappenden

Hi Jay & Armin,

Thanks to both of you for your help with this.

I'm going to have to live with the fact that VB.NET doesn't support this
functionality.

I will submit the wish - lets hope it gets in.

Cheers again,

Richard
 
T

Tom Shelton

I think *you* don't understand it - but don't let us start this...

from CMessage, so it must work. Consequently you can not create this
limitation.

Armin,

I think what Richard is getting at is that C++ lets you specialize the
parameter type. In other words, you can create classes that derive from
the base, but only accept as parameters a specific subclass.

That doesn't sound clear to me... Basically, he's saying is that in his
example you have the base message type and a base message manager...

Public MustInherit Class BaseMessage
Public MustOverride Sub SendMessage(ByVal Text As String)
End Class

Public MustInherit Class BaseMsgManager
Public MustOverride Sub ProcessMessage(ByVal Message As BaseMessage)
End Class

From that you can create specialized types to deal with specific
subclasses...

Public Class SnailMail
Inherits BaseMessage

Public Overrides Sub SendMessage(ByVal Text As String)
Call PayPostage()
Call PutInMailBox()
End Sub
End Class

Public Class SnailMailManager
Public Overrides Sub ProcessMessage(ByVal Message As SnailMail)
Message.SendMessage("Hello, World!")
End Sub
End Class

In C++, you are createing a specialized version of the manager class
that will only deal with a specific subclass of BaseMessage. You can't
do that directly in .NET. What Richard could do is something like:


Public Class SnailMailManager
Public Overrides Sub ProcessMessage(ByVal Message As BaseMessage)
If TypeOf Message Is SnailMail Then
Me.ProcessMessage(DirectCast(Message, SnailMail))
Else
Throw New ArgumentException("Type of Message Must Be
SnailMail)
End If
End Sub


Public Overloads Sub ProcessMessage(ByVal Message As SnailMail)
Message.SendMessage("Hello, World!")
End Sub

End Class


Though that does seem a little extra work for something that some
languages do automatically.
 
C

Cor

Hi Jay,
This reminds me of the story of three blind men who stumble upon an
elephant

what those technical reasons are. I do know that it will make the work of
"that elephant" a little more challenging.

:))

I was just reading it, not what you where all talking about, I show you only
my laugh on my face when I was reading your words about the elephant. (and
the elephant has no meaning I don't know if it is a challange)

Cor
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top