sobre herencia multiple

11/04/2005 - 19:58 por olopeich | Informe spam
Epa!

Tengo un problema q no se como enfocar; es mas bien teorico, ahi va:

Tengo una aplicacion con clientes, cada cliente es un objeto con sus
propiedades metodos y tal.

En un momento dado tengo q representar esos clientes con un treeview. Lo
que hago es derivar una clase de TreeNode llamada mTreeNode donde añado
las propiedades que me interesan de la clase clientes; de este modo
cuando hago click en un nodo del arbol tengo acceso a todos los datos de
ese cliente, q visualizo o manipulo con ayuda de otros controles. Hasta
aqui vamos bien... o mejor dicho medio bien porque al no tener herencia
multiple (es la unica manera q se me ocurre de resolver el problema) no
puedo hacer un

class mTreenode
inherits Treenode, Clientes

.
.
.

End class

porque evidentemente mTreeNode tiene q heredar de Treenode, sino el
treeview peta. De esta guisa tengo q duplicar todo el codigo de clientes
en la clase mTreeView q me interese en vez de simplemente heredar.

Si mas adelante tengo otra representacion distinta de Cliente (yo q se,
con listbox por ejemplo) tengo q volver a hacer lo mismo: crear otra
clase que herede del tipo de dato que ese control pida y duplicar todo
el codigo de Cliente en esa clase.

Y digo yo: hay alguna manera mas elegante de resolver esto en vb .net???
me da la impresion de estar obviando algo muy basico pero no atino...

Saludos y mil gracias a todos.

Preguntas similare

Leer las respuestas

#11 Tristan
16/04/2005 - 01:18 | Informe spam
Es por eso q se resuelven en ejecucion (en late binding).



No, ahí es donde viene el error. No se resuelven en late binding. Tampoco
del todo en early. Se mantiene una tabla virtual (por eso se llaman métodos
virtuales en C++ o C#) con las direcciones de todos los métodos
correspondientes a las clases a las que se podría llamar. La llamada es tan
solo un direccionamiento indexado. Nada que ver con lo que sería una
auténtica resolución en late binding como la que se produce al utilizar
reflection.

Por lo demás con las interfaces el sistema es el mismo que con la herencia.

vamos a ver, quiza aqui tenga yo el agujeron mental. Yo tengo una clase
q implementa ienumerable. Automaticamente mi clase hereda el codigo q
permitira a mi clase ser utilizada en un for each o por contra tengo q
implementar ese codigo por mi mismo.



Por supuesto tienes que implementar el código de IEnumerable. No es posible
saber de antemano de que forma recorrerás la colección. Tu tienes que
indicar de que forma se hará. Tan solo heredarías el código de IEnumerable
si tu clase desciende de una clase que implemente IEnumerable. Lo importante
es que la sentencia For Each sabe que los métodos estarán disponibles,
conoce sus direcciones, los tipos de sus parámetros y su retorno. Está
creada la plantilla, pero el programador tiene que rellenarla.

claro, es q con herencia simple y solo con ella la cosa esta
extremadamente limitada.



No es realmente cierto. No hay tal limitación. Que yo sepa, no hay ningún
contexto en que sea realmente necesaria la herencia múltiple. Siempre hay
formas de lograr lo mismo mediante herencia simple.

esto tambien lo sabia pero como nunca he utilizado un lenguaje q me
permita herencia multiple no veo lso problemas q puede acarrear. Los
problemas los puedo imaginar pero ya sabes, no haberlso padecido hace q
parezcan menores.



Tú piensa en el caso que te he dicho. Parte de dos clases A y B. Por derivar
de Object las dos disponen de un método ToString(). Imagina que A devuelve
en ToString() el valor "A". B por el contrario devuelve "B". Ahora imagina
una clase C, que herede de las dos. ¿Para C, cual sería el valor devuelto
por ToString()?. La única solución sería especificar por cada método común
de C, la rama de la que hereda. Así funciona en C++. Pero como puedes
imaginar cuando la jerarquía se complica la cosa se hace muy difícil de
manejar. No, no creo que sea una buena idea heredar código de dos ramas. Por
el contrario, aunque con interfaces también existe posibilidad de
ambigüedad, es mucho menor y sobre todo más clara y fácil de mantener.

En cualquier caso, el caso que tu necesitas es la prueba de que no es
necesario heredar código de dos ramas. Una instancia de una clase puede
mantener una referencia a una instancia de otra. Entre las dos, heredan
código de las dos ramas. Todo eso sin los conflictos anteriores.

Juan Carlos Badiola
MVP - C#
Respuesta Responder a este mensaje
#12 Tristan
16/04/2005 - 11:27 | Informe spam
vamos a ver, quiza aqui tenga yo el agujeron mental. Yo tengo una clase
q implementa ienumerable. Automaticamente mi clase hereda el codigo q
permitira a mi clase ser utilizada en un for each o por contra tengo q
implementar ese codigo por mi mismo.





Por cierto, esta parte es muy importante y tal vez no te va a quedar clara
con mi explicación anterior. A ver si lo puedo explicar mejor.

Esto sería un ejemplo de sentencia For Each:

Dim primos() As Integer = {1, 2, 3, 5, 7, 11}

Dim primo As Integer
For Each primo In primos
MsgBox(primo)
Next

El compilador, después de comprobar que la clase es IEnumerable, convertirá
For Each en algo así:

Dim primo As Integer
Dim enumerador As IEnumerator = primos.GetEnumerator()
enumerador.Reset()
While enumerador.MoveNext
primo = DirectCast(enumerador.Current, Integer)
MsgBox(primo)
End While

Los miembros de la interface IEnumerator, han sido definidos por los
programadores de la clase Array. Lo importante es que For Each sabe que
existen, independientemente de como se implementen. El compilador puede
comprobar y optimizar el código, puesto que conoce las direcciones de los
miembros.

Juan Carlos Badiola
MVP - C#
Respuesta Responder a este mensaje
#13 olopeich
20/04/2005 - 15:45 | Informe spam
No, ahí es donde viene el error. No se resuelven en late binding. Tampoco
del todo en early. Se mantiene una tabla virtual (por eso se llaman métodos
virtuales en C++ o C#) con las direcciones de todos los métodos
correspondientes a las clases a las que se podría llamar. La llamada es tan
solo un direccionamiento indexado. Nada que ver con lo que sería una
auténtica resolución en late binding como la que se produce al utilizar
reflection.



anda la osa, no sabia yo esto. En los libros q he consultado no hacen
esa distincion. Simplente lo trataban como late binding y listo.

que es la reflexion? otra de esas cosas q nunca he usado...

Por supuesto tienes que implementar el código de IEnumerable. No es posible
saber de antemano de que forma recorrerás la colección. Tu tienes que



ya me imaginaba

indicar de que forma se hará. Tan solo heredarías el código de IEnumerable
si tu clase desciende de una clase que implemente IEnumerable. Lo importante



herendando la clase entera supongo.

es que la sentencia For Each sabe que los métodos estarán disponibles,
conoce sus direcciones, los tipos de sus parámetros y su retorno. Está
creada la plantilla, pero el programador tiene que rellenarla.



entiendo.


Por cierto, esta parte es muy importante y tal vez no te va a quedar


clara
con mi explicación anterior. A ver si lo puedo explicar mejor.


.
.
.
Los miembros de la interface IEnumerator, han sido definidos por los
programadores de la clase Array. Lo importante es que For Each sabe



el ejemplo esta super claro, y es q es un ejemplo q siempre viene en los
libros de oop para explicar la utilidad de los interfaces, sin embargo
no veo su uso mas alla del caso for each y similares; quiero decir, q no
veo la necesidad en la vida real de que yo cree una nueva interface ni
tampoco veo su relacion con la herencia... bueno, la relacion la intuyo
pero siempre he asociado a la herencia con herencia de codigo...
Respuesta Responder a este mensaje
#14 Tristan
22/04/2005 - 00:03 | Informe spam
el ejemplo esta super claro, y es q es un ejemplo q siempre viene en los
libros de oop para explicar la utilidad de los interfaces, sin embargo no
veo su uso mas alla del caso for each y similares; quiero decir, q no veo
la necesidad en la vida real de que yo cree una nueva interface ni tampoco
veo su relacion con la herencia... bueno, la relacion la intuyo pero
siempre he asociado a la herencia con herencia de codigo...



Pues como te decía, no tiene que ver con la herencia de código, pero si con
la delegación, con el polimorfismo, que es la aplicación más útil de la
herencia. Realmente hay miles de casos en los que las interfaces son
necesarias.

Los eventos, es decir el patrón observador, son una aplicación muy típica de
las interfaces. En lenguajes como Java, donde no existen los delegados, los
eventos se implementan a base de interfaces. Es decir, siempre que el
trabajo de una clase se debe delegar en un procedimiento de otra, de una
forma o de otra, lo que estás utilizando son interfaces.

En remoting, para no tener que pasar el código de una clase remota a su
cliente, las interfaces son muy útiles. Lo único que tiene que "viajar" es
la interface del objeto, que varía poco.

En una clase que ordene, un Sort, la comparación se puede implementar
mediante una interface, IComparable, que realice el trabajo externo de
comparación. También los delegados pueden hacer lo mismo. Pero es que en
realidad delegados e interfaces son primos hermanos.

En fin, te aseguro que las interfaces son muy útiles. En tu caso, yo
implementaría una interface para comunicar todos los objetos de interface
gráfica, con tu clase cliente. De esta forma, los objetos de interface solo
necesitan conocer la interface del objeto cliente, no su implementación. Y
quien dice conocer, dice tener en la misma máquina.

Bueno, como te decía, creo que echando un vistazo a la multitud de
interfaces que existen en .net, o por supuesto en otros entornos OOP como
Java, te puede hacer una idea de cual es su utilidad. Imagina de que forma
podrías sustituirlos por clases, y verás que es sencillamente imposible.

Juan Carlos Badiola
MVP - C#
email Siga el debate Respuesta Responder a este mensaje
Ads by Google
Help Hacer una pregunta AnteriorRespuesta Tengo una respuesta
Search Busqueda sugerida