Crear una clase descendiente de TInifile
Hola a todos
Estoy intentando crear una clase descendiente de TIniFile, con la idea de tener una unidad para gestionar la configuración de laS aplicaciones de tal forma que si se le pasa alguna clase descendiente de un TINIFILE, trabaje con esta clase, en caso de no declara nada que trabaje con la clase general de TINIFile. Este es el código para la unidad de configs.pas
Y la forma de utilizarlo en cualquier parte del programa:
y así es como redefino una nueva clase descendiente de TInifile
Y aquí es donde viene el problema, tal como esta todo esto declarado, el código del constructor de la clase descendiente (TMyIniFile.Create) no se ejecuta al crear la instancia del objeto desde la variable ClassIniFile y pasa directamente a ejecutar el constructor de la clase padre (TiniFile.create). Por el contrario si en el procedimiento config lo pusiera de esta forma, entonces si que funciona perfectamente:
Pero de esta forma no quiero ponerlo, por que así estaría forzado a tener que añadir siempre en el uses de la unidad configs la unidad que contiene la clase descendiente, pudiendo estar unas veces incluida en el proyecto y otras veces no. Me explico mas, mi idea es si en una determinada aplicación que utiliza la unidad CONFIGS le agrego la otra unidad con la clase descendiente, entonces esa aplicación usara esa clase descendiente para gestionar como y donde guardar la configuración, pero si en otra aplicación distinta que también usa la misma unidad CONFIGS, no tiene agregada ninguna unidad descendiente de TINIFILE, entonces se pretende que utilice la clase genérica de TINIFILE. No se si alguien me puede arrojar luz sobre por que no se ejecuta la clase constructora descendiente al llamarla desde la variable que contiene la clase descendiente. Gracias por vuestro tiempo y saludos |
Creo que el problema está en que el create de la clase base:
Está definido de esta forma. Ni virtual, ni abstract,... Si añades un método como este a tu clase:
Comprobará que realmente el objeto es de la clase correcta, porque al ejecutar este código:
Realmente ejecuta el método:
|
Hola Neftali, gracias por responder!!
Si después de unas cuantas pruebas llegue a esa misma conclusión, el problema se encuentra en esta definición class of TInifile que es la que determina el orden de búsqueda, y es que al no poder hacer override sobre el constructor por que la clase padre no lo permite, si el compilador se encuentra con varias clases constructoras declaradas de forma idéntica, entonces la búsqueda de procesos la realiza internamente a algo parecido a una lista con esta forma: Código:
1:TINIFile{ constructor Create(const FileName: string); } Y lo solucione creando una clase intermedia (TAvIniFile) donde se define el constructor de forma virtual para así poder sobre-escribirlo en las clases descendientes,
y finalmente sustituyo la declaración de classInifile por TclassInifile = class of TAvInifile, de esta forma la lista de búsqueda quedaría así: Código:
1: clases descendientes a TAvIniFile con el constructor sobre-escrito, aquí se incluye TMyIniFile Un saludo |
Hola a todos,
Ha estado bien visto esto último, bucanero. Yo, en mi ignorancia, iba a responder de entrada que el método constructor de tu clase INI tenía que ser "override" y no "overload". Pero, al probarlo aquí, me dí cuenta de que no era tan sencillo como hacer esto... no alcancé yo hasta donde llegó el compañero Neftalí, que fue descubrir que el constructor de la clase TIniFile no puede sobrescribirse. Vamos, ni alcabcé yo donde el Neftalí llegó, ni por supuesto se me ocurrió pensar en hacer lo que tú al final has hecho. Está bien saberlo. :) |
Cita:
Si, yo también me di cuenta del cambio de palabra overload/override David, pero el problema está en la definición de las clases base, que como he dicho no están definidas para que se puedan "sobreescribir". Como bien dices, al realizar el cambio da el error de "Cannot override a non-virtual method". |
Puedes usar reintroduce
|
Gracias DEC y movorack por responder
Cita:
En cuanto al reintroduce también lo intente y el resultado fue el mismo. En tu código te ha funcionado porque has llamado directamente al método create de la clase TMyIniFile, y de este modo incluso con el overload funciona Cita:
Gracias a todos por dedicarle tiempo a esta cuestión Un saludo |
hola bucanero.
Sugiero que utilices la RTTI. Para ello debes cambiar tu codigo de la unidad configs asi:
y tus unidades descendientes, algo asi:
|
Igual, amigo bucanero, creo que vas por un lado que no es. Lo que tu quieres implementar, puede salir mejor utilizando interfaces ==> El problema con el caso específico que propones es que las interfaces no admiten constructores....
|
Al fin no nos tomaron la foto donde TopX, Tu y yo estábamos revisando este hilo.
|
Gracias gatosoft por responder
Cita:
Viendo tu código me encuentro que en la linea donde debe de buscar y localizar la classe devuelve NIL y no la encuentra. Cita:
Pero aquí aparece otro problema, y es que el procedimiento RegisterClass(AClass: TPersistentClass) requiere que la clase a registrar sea descendiente de TPersistentClass, y yo estoy intentando registrar una clase descendiente de TINIFile que a su vez es una una classe descendiente directamente de TObject y por este motivo el compilador da el siguiente error E2010 Incompatible types: 'TPersistentClass' and 'class of TMyIniFile' Cita:
Porque mi idea final a parte de lo ya explicado es sobre-escribir los métodos de lectura/escritura de mi clase descendiente de TINIFile, para que en vez de guardar los datos en un fichero los guarde directamente en la BBDD, manteniendo la máxima compatibilidad con el componente original para que en determinados casos que no quiera utilizar mi componente propio y/o guardar en la BBDD puede usar directamente un TINIFile. |
Hola Movorack, realmente no se a que te refieres con esto :confused:....
Cita:
|
Cita:
en el hilo se dice: Cita:
Cita:
Existe una técnica que te puede servir y es la de interceptores, pero como todo, no es para abusar de ella. y funciona mas o menos asi: En la clausula Uses defines la unidad Inifiles, que contiene la implementación nativa del componente. Después, defines la clase "interceptora" TIniFile (Tiene el mismo nombre de la nativa) la cual hereda de System.IniFiles.TIniFile (debes especificar la unidad). Y en esta nueva clase, puedes definir nueva funcionalidad y sobreescribir la existente.
en tu caso, modificarias tu codigo aqsí..
revisa |
igual, no está de mas pensar en la solución tradicional: Definir una clase derivada de TIniFile, con la funcionalidad que requieres y a partir de ella definir los descendientes de los que hablas.
Cuando tienes una clase padre y muchos posibles descendientes que desconoces, es cuando comienzas a pensar en clases abstractas o en interfaces. |
Cita:
Es que Movorack, Topx y yo, trabajamos en el mismo piso.... |
Cita:
|
Muchas gracias gatosoft por toda la información aportada
Cita:
Cita:
Cita:
Después he realizado una pequeña modificación a tu código, para que no sea necesario hacer la búsqueda de la clase por su nombre, ya que a priori se tiene ya la clase y así se pueda utilizar directamente sin necesidad de hacer su búsqueda. Y así, si ha funcionado también:
Gracias nuevamente a todos los que han dedicado parte de su tiempo a este hilo Un saludo |
La franja horaria es GMT +2. Ahora son las 01:17:50. |
Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi