{"id":473,"date":"2023-09-20T22:27:34","date_gmt":"2023-09-20T21:27:34","guid":{"rendered":"https:\/\/jorgeturiel.es\/?page_id=473"},"modified":"2025-05-28T09:51:52","modified_gmt":"2025-05-28T08:51:52","slug":"introduccion-al-lenguaje-pascal-moderno-para-programadores","status":"publish","type":"page","link":"https:\/\/jorgeturiel.es\/?page_id=473","title":{"rendered":"Introducci\u00f3n al lenguaje Pascal moderno para programadores"},"content":{"rendered":"\n<p>Mucha gente considera el lenguaje Pascal, como un lenguaje obsoleto, ya que en internet hay muchos recurso que hablan sobre el lenguaje Pascal, pero hablan sobre el \u00abviejo\u00bb Pascal.<\/p>\n\n\n\n<p>Michalis Kamburelis, creador del motor gr\u00e1fico <a rel=\"noreferrer noopener\" href=\"https:\/\/castle-engine.io\" target=\"_blank\">Castle Engine<\/a>, escribi\u00f3 una gu\u00eda muy concisa y sencilla en la que muestra las caracter\u00edsticas de este lenguaje.<\/p>\n\n\n\n<p>El texto original se puede encontrar <a rel=\"noreferrer noopener\" href=\"https:\/\/castle-engine.io\/modern_pascal\" target=\"_blank\">aqu\u00ed<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u00bfPor qu\u00e9?<\/h2>\n\n\n\n<p id=\"tw-target-text\">Hay muchos libros y recursos sobre Pascal, pero muchos de ellos hablan sobre el antiguo Pascal, sin clases, unidades o gen\u00e9ricos. As\u00ed que escrib\u00ed esta r\u00e1pida introducci\u00f3n a lo que llamo Object Pascal moderno. La mayor\u00eda de los programadores que lo usan realmente no lo llaman \u00abObjeto Pascal moderno\u00bb, simplemente lo llamamos \u00abnuestro Pascal\u00bb. Pero al presentar el lenguaje, creo que es importante enfatizar que es un lenguaje moderno y orientado a objetos. Evolucion\u00f3 mucho desde el viejo (Turbo) Pascal que mucha gente aprendi\u00f3 en las escuelas hace mucho tiempo. En cuanto a las funciones, es bastante similar a C++, Java o C#.   <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Tiene todas las caracter\u00edsticas modernas que espera: clases, unidades, interfaces, gen\u00e9ricos&#8230;     <\/li>\n\n\n\n<li>Est\u00e1 compilado en un c\u00f3digo nativo r\u00e1pido.<\/li>\n\n\n\n<li>Es muy seguro.<\/li>\n\n\n\n<li>De alto nivel, pero tambi\u00e9n puede ser de bajo nivel si lo necesitas<\/li>\n<\/ul>\n\n\n\n<p>Tambi\u00e9n tiene un compilador excelente, port\u00e1til y de c\u00f3digo abierto llamado Free Pascal, <a href=\"http:\/\/freepascal.org\">http:\/\/freepascal.org<\/a>. Y un entorno de desarrollo integrado o <a href=\"https:\/\/es.wikipedia.org\/wiki\/Entorno_de_desarrollo_integrado\">IDE <\/a>que lo acompa\u00f1a (editor, depurador, una biblioteca de componentes visuales, dise\u00f1ador de formularios) llamado Lazarus <a href=\"http:\/\/lazarus.freepascal.org\/\">http:\/\/lazarus.freepascal.org\/<\/a>. Yo mismo, soy el creador de <em>Castle Game Engine<\/em>, <a href=\"https:\/\/castle-engine.io\/\">https:\/\/castle-engine.io\/<\/a>, que es un motor de juegos 3D y 2D de c\u00f3digo abierto que utiliza Pascal moderno para crear juegos en muchas plataformas (Windows, Linux, macOS, Android, iOS, Nintendo Switch; tambi\u00e9n viene WebGL). <\/p>\n\n\n\n<p>Esta introducci\u00f3n est\u00e1 dirigida principalmente a programadores que ya tienen experiencia en otros lenguajes. No cubriremos aqu\u00ed los significados de algunos conceptos universales, como \u00abqu\u00e9 es una clase\u00bb, solo mostraremos c\u00f3mo hacerlo en Pascal.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">B\u00e1sico<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Hola Mundo<\/h3>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-} \/\/ Usa esta l\u00ednea en todos los recursos\n\nprogram MyProgram; \/\/ guarda este programa como myprogram.lpr\nbegin\n  WriteLn('Hola Mundo!');\nend.<\/pre><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Este es un programa completo que puede compilar y ejecutar. Este es un programa de l\u00ednea de comandos, por lo que en cualquier caso\u2009\u2014\u2009simplemente ejecute el ejecutable compilado desde la l\u00ednea de comandos.<\/li>\n\n\n\n<li>Si usa la l\u00ednea de comandos FPC, simplemente cree un nuevo archivo <em><code>myprogram.lpr<\/code><\/em> y ejecute <em><code>fpc myprogram.lpr<\/code><\/em><\/li>\n\n\n\n<li>Si usas Lazarus, cree un nuevo proyecto (men\u00fa Proyecto \u2192 Nuevo proyecto \u2192 Programa Simple). Gu\u00e1rdelo como <em><code>myprogram<\/code><\/em> y pegue este c\u00f3digo fuente como archivo principal. Compilar utilizando el elemento de men\u00fa Ejecutar \u2192 Compilar.<\/li>\n\n\n\n<li>Este es un programa de l\u00ednea de comandos, por lo que en cualquier caso,\u2009simplemente ejecute el ejecutable compilado desde la l\u00ednea de comandos. <\/li>\n<\/ul>\n\n\n\n<p>El resto de este art\u00edculo habla sobre el lenguaje <em>Object Pascal<\/em>, as\u00ed que no esperes ver nada m\u00e1s elegante que la l\u00ednea de comandos. Si quiere ver algo genial, simplemente cree un nuevo proyecto <em>GUI <\/em>en Lazarus (Proyecto \u2192 Nuevo proyecto \u2192 Aplicaci\u00f3n). Listo\u2009\u2014\u2009una aplicaci\u00f3n GUI en funcionamiento, multiplataforma, con un aspecto nativo en todas partes, que utiliza una c\u00f3moda biblioteca de componentes visuales. El compilador Lazarus y Free Pascal vienen con muchas unidades listas para redes, GUI, base de datos, formatos de archivo (XML, json, im\u00e1genes&#8230;), subprocesos y todo lo que pueda necesitar. Ya mencion\u00e9 mi genial <a rel=\"noreferrer noopener\" href=\"http:\/\/castle-engine.io\/\" target=\"_blank\">Castle Game Engine<\/a> antes \ud83d\ude42<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Compiladores FPC  \u00abmodos de sintaxis\u00bb<\/h3>\n\n\n\n<p>Este libro, todo el texto y los ejemplos de Pascal, ha sido escrito para ser compatible con dos compiladores modernos de Pascal:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Free Pascal Compiler (FPC), compilador de Pascal de c\u00f3digo abierto, utilizado tambi\u00e9n por el IDE Lazarus.<\/li>\n\n\n\n<li>Delphi, un compilador de Pascal propietario de Embarcadero.<\/li>\n<\/ul>\n\n\n\n<p><br>En este libro, elegimos dar soporte completo a ambos compiladores. Al igual que en Castle Game Engine, damos soporte a ambos, y es tu elecci\u00f3n cu\u00e1l prefieres. Nuestra integraci\u00f3n continua (ver <a href=\"https:\/\/castle-engine.io\/github_actions\">https:\/\/castle-engine.io\/github_actions<\/a>) asegura que todos los ejemplos realmente compilen con ambos compiladores.<\/p>\n\n\n\n<p><br>Para complicar un poco las cosas, el compilador FPC tiene m\u00faltiples \u00abmodos de sintaxis\u00bb. En este libro, decidimos mostrar el modo de sintaxis ObjFpc, que es recomendado por los desarrolladores de FPC y es el predeterminado para los nuevos proyectos de Pascal creados con Lazarus o Castle Game Engine. Es un poco diferente del modo de sintaxis Delphi, que es el m\u00e1s compatible con el lenguaje Pascal tal como lo implementa Delphi. Escribimos una comparaci\u00f3n detallada <a href=\"https:\/\/jorgeturiel.es\/?page_id=1041\">aqu\u00ed<\/a>.<br><\/p>\n\n\n\n<p>\u00a1Pero no querr\u00e1s leer sobre estas diferencias ahora, si reci\u00e9n est\u00e1s comenzando a aprender Pascal!<\/p>\n\n\n\n<p><br>Las diferencias son menores, tanto entre compiladores como entre el modo ObjFpc de FPC y el modo Delphi. Solo ten en cuenta que puedes ver algunas cl\u00e1usulas {$ifdef FPC} \u2026\u200b {$endif} en los ejemplos, que hacen que el c\u00f3digo sea v\u00e1lido tanto para el modo ObjFpc de FPC como para Delphi. Usar {$ifdef FPC_OBJFPC} \u2026\u200b {$endif} en algunos de estos casos podr\u00eda ser m\u00e1s preciso, pero parecer\u00eda a\u00fan m\u00e1s complicado. Si tu proyecto solo se dirige a uno de estos compiladores, puedes simplificar tu c\u00f3digo, simplemente elige la variante para tu compilador y elimina las partes {$ifdef \u2026\u200b}, {$endif}.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Funciones procedimientos y tipos primitivos<\/h3>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\n\nprogram MyProgram;\n\nprocedure MyProcedure(const A: Integer);\nbegin\n  WriteLn('A + 10 es: ', A + 10);\nend;\n\nfunction MyFunction(const S: string): string;\nbegin\n  Result := S+ 'las cadenas (strings) se gestionan automaticamente';\n\nend;\n\nvar\n  X: Single;\nbegin\n  WriteLn(MyFunction('Note: '));\n  MyProcedure(5);\n\n\n  \/\/ Divisi\u00f3n usando \"\/\" siempre devuelve un Float como resultado. Use \"div\" para dividir y obtener un integer\n  X := 15 \/ 5;\n  WriteLn('X is now: ', X); \/\/ notaci\u00f3n cient\u00edfica\n  WriteLn('X is now: ', X:1:2); \/\/ 2 decimales\nend.<\/pre><\/div>\n\n\n\n<p id=\"tw-target-text\">Para devolver un valor de una funci\u00f3n, asigne algo a la variable m\u00e1gica <em>Result<\/em>. Puede leer y configurar <em>Result<\/em> libremente, como una variable local.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">function MyFunction(const S: string): string;\nbegin\n  Result := S + 'algo';\n  Result := Result + ' \u00a1algo m\u00e1s!';\n  Result := Result + ' \u00a1y m\u00e1s!';\nend;<\/pre><\/div>\n\n\n\n<p id=\"tw-target-text\">Tambi\u00e9n puede tratar el nombre de la funci\u00f3n (como <code><em>MyFunction<\/em><\/code> en el ejemplo anterior) como la variable a la que puede asignar datos. Pero lo desaconsejar\u00eda en el c\u00f3digo nuevo, ya que parece \u00absospechoso\u00bb cuando se usa en el lado derecho de la expresi\u00f3n de asignaci\u00f3n. Simplemente use <em>Result <\/em>siempre cuando quiera leer o configurar el resultado de la funci\u00f3n.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">function SumIntegersUntilZero: Integer;\nvar\n  I: Integer;\nbegin\n  Readln(I);\n  Result := I;\n  if I &lt;&gt; 0 then\n    Result := Result + SumIntegersUntilZero();\nend;<\/pre><\/div>\n\n\n\n<p id=\"tw-target-rmn\">Puede llamar a <em><code>Exit<\/code> <\/em>para finalizar la ejecuci\u00f3n del procedimiento o funci\u00f3n antes de que llegue al final final;. Si llama a <em><code>Exit<\/code> <\/em>sin par\u00e1metros en una funci\u00f3n, devolver\u00e1 lo \u00faltimo que configur\u00f3 como <em>Result<\/em>. Tambi\u00e9n puede usar la construcci\u00f3n <em><code>Exit(X<\/code>)<\/em>, para establecer el resultado de la funci\u00f3n y salir ahora\u2009\u2014\u2009esto es como devolver la construcci\u00f3n X en lenguajes similares a C.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">function AddName(const ExistingNames, NewName: string): string;\nbegin\n  if ExistingNames = '' then\n    Exit(NewName);\n  Result := ExistingNames + ', ' + NewName;\nend;<\/pre><\/div>\n\n\n\n<p>Tenga en cuenta que el resultado de la funci\u00f3n puede descartarse. Cualquier funci\u00f3n puede usarse como un procedimiento. Esto tiene sentido si la funci\u00f3n tiene alg\u00fan efecto secundario (por ejemplo, modifica una variable global) adem\u00e1s de calcular el resultado. Por ejemplo:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">var\n  Count: Integer;\n  MyCount: Integer;\n\nfunction CountMe: Integer;\nbegin\n  Inc(Count);\n  Result := Count;\nend;\n\nbegin\n  Count := 10;\n  CountMe; \/\/ EL resultado de la funci\u00f3n se descarta, pero la funci\u00f3n es ejecutada, Count ahora es 11\n  MyCount := CountMe; \/\/ uso del resultado de la funci\u00f3n, MyCount es igual a Count, el cual ahora es 12\nend.<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Testing (if)<\/h3>\n\n\n\n<p id=\"tw-target-text\">Use <code><em>if .. then o if .. then .. else<\/em><\/code> para ejecutar alg\u00fan c\u00f3digo cuando se cumpla alguna condici\u00f3n. A diferencia de los lenguajes tipo C, en Pascal no tienes que envolver la condici\u00f3n entre par\u00e9ntesis.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">var\n  A: Integer;\n  B: boolean;\nbegin\n  if A &gt; 0 then\n    DoSomething;\n\n  if A &gt; 0 then\n  begin\n    DoSomething;\n    AndDoSomethingMore;\n  end;\n\n  if A &gt; 10 then\n    DoSomething\n  else\n    DoSomethingElse;\n\n  \/\/ equivalente a lo de encima\n  B := A &gt; 10;\n  if B then\n    DoSomething\n  else\n    DoSomethingElse;\nend;<\/pre><\/div>\n\n\n\n<p id=\"tw-target-text\">El <em><code>else<\/code> <\/em>est\u00e1 emparejado con el \u00faltimo <em><code>if<\/code>.<\/em> Entonces esto funciona como esperas:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">if A &lt;&gt; 0 then\n  if B &lt;&gt; 0 then\n    AIsNonzeroAndBToo\n  else\n    AIsNonzeroButBIsZero;<\/pre><\/div>\n\n\n\n<p id=\"tw-target-text\">Si bien el ejemplo con el <em><code>IF<\/code><\/em> anidado anterior es correcto, a menudo es mejor colocar el <em>IF<\/em> anidado dentro de un bloque <code><em>Begin<\/em>\u2026 <em>End<\/em><\/code> en tales casos. Esto hace que el c\u00f3digo sea m\u00e1s obvio para el lector y seguir\u00e1 siendo obvio incluso si estropeas la sangr\u00eda. La versi\u00f3n mejorada del ejemplo se encuentra a continuaci\u00f3n. Cuando agrega o elimina alguna otra cl\u00e1usula en el c\u00f3digo a continuaci\u00f3n, es obvio a qu\u00e9 condici\u00f3n se aplicar\u00e1 (a la prueba A o la prueba B), por lo que es menos propenso a errores.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">if A &lt;&gt; 0 then\nbegin\n  if B &lt;&gt; 0 then\n    AIsNonzeroAndBToo\n  else\n    AIsNonzeroButBIsZero;\nend;<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Operadores l\u00f3gicos, relacionales y bit a bit<\/h3>\n\n\n\n<p id=\"tw-target-text\">Los operadores l\u00f3gicos se llaman <code><em>and<\/em>, <em>or<\/em>, <em>not<\/em>, <em>xor<\/em><\/code>. Su significado es probablemente obvio (busque \u00abo exclusivo\u00bb si no est\u00e1 seguro de lo que hace <em><code>xor<\/code> <\/em>:)). Toman argumentos booleanos y devuelven un booleano. Tambi\u00e9n pueden actuar como operadores bit a bit cuando ambos argumentos son valores enteros, en cuyo caso devuelven un n\u00famero entero.<\/p>\n\n\n\n<p id=\"tw-target-rmn\">Los operadores relacionales (de comparaci\u00f3n) son <em><code>=, &lt;&gt;, &gt;, &lt;, &lt;=, &gt;=<\/code><\/em>. Si est\u00e1 acostumbrado a lenguajes similares a C, tenga en cuenta que en Pascal compara dos valores (verifique si son iguales) usando un solo car\u00e1cter de igualdad <code><em>A = B <\/em><\/code>(a diferencia de C donde usa<em> <\/em><code><em>A == B)<\/em><\/code>. El operador de asignaci\u00f3n especial en Pascal es<code><em> :=<\/em><\/code>. <\/p>\n\n\n\n<p id=\"tw-target-text\">Los operadores l\u00f3gicos (o bit a bit) tienen mayor preferencia que los operadores relacionales. Es posible que deba usar par\u00e9ntesis alrededor de algunas expresiones para tener el orden deseado de los c\u00e1lculos.<\/p>\n\n\n\n<p>Por ejemplo, esto es un error de compilaci\u00f3n:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">var\n  A, B: Integer;\nbegin\n  if A = 0 and B &lt;&gt; 0 then ... \/\/ ejemplo incorrecto\n\n<\/pre><\/div>\n\n\n\n<p id=\"tw-target-text\">Lo anterior falla al compilar, porque el compilador primero quiere realizar un bit a bit y en el medio de la expresi\u00f3n: <code><em>(0 and B)<\/em><\/code>. Esta es una operaci\u00f3n bit a bit que devuelve un valor entero. Luego, el compilador aplica el operador = que produce un valor booleano <em><code>A = (0 and B)<\/code><\/em>. Y finalmente, el error de \u00abtipo no coincidente\u00bb surge despu\u00e9s de intentar comparar el valor booleano<em><code> A = (0 and B)<\/code><\/em> y el valor entero 0.<\/p>\n\n\n\n<p>Esto es correcto:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">var\n  A, B: Integer;\nbegin\n  if (A = 0) and (B &lt;&gt; 0) then ...<\/pre><\/div>\n\n\n\n<p id=\"tw-target-text\">Se utiliza la evaluaci\u00f3n de \u00abcortocircuito\u00bb. Considere esta expresi\u00f3n:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">if MyFunction(X) and MyOtherFunction(Y) then...<\/pre><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li> Est\u00e1 garantizado que <em><code>MyFuncion(X)<\/code> se evaluar\u00e1 primero.<\/em><\/li>\n\n\n\n<li>Y si <em><code>MyFunction(x)<\/code><\/em> devuelve falso, entonces la valor de la expresi\u00f3n ser\u00e1 falso, y <em><code>MyOtherFunction(Y)<\/code><\/em> no se ejecutar\u00e1 en absoluto.<\/li>\n\n\n\n<li>De manera an\u00e1loga es para el operador <em><code>OR<\/code><\/em>. Si se sabe que la expresi\u00f3n es verdadera (porque el primer operador es verdadero), el segundo operador no se evaluar\u00e1.<\/li>\n<\/ul>\n\n\n\n<p>Esto es particularmente \u00fatil cuando se escriben expresiones como:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">if (A &lt;&gt; nil) and A.IsValid then...<\/pre><\/div>\n\n\n\n<p id=\"tw-target-rmn\">Esto funcionar\u00e1 bien, incluso cuando A es nulo. La palabra clave <em><code>nil<\/code><\/em> es un puntero igual a cero (cuando se representa como un n\u00famero). Se llama puntero nulo en muchos otros lenguajes de programaci\u00f3n.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Prueba de expresi\u00f3n \u00fanica para valores m\u00faltiples (case)<\/h3>\n\n\n\n<p id=\"tw-target-text\">Si se debe ejecutar una acci\u00f3n diferente dependiendo del valor de alguna expresi\u00f3n, entonces la instrucci\u00f3n<code> <em>case .. of .. end<\/em><\/code> es \u00fatil.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">case SomeValue of\n  0: DoSomething;\n  1: DoSomethingElse;\n  2: begin\n       IfItsTwoThenDoThis;\n       AndAlsoDoThis;\n     end;\n  3..10: DoSomethingInCaseItsInThisRange;\n  11, 21, 31: AndDoSomethingForTheseSpecialValues;\n  else DoSomethingInCaseOfUnexpectedValue;\nend;<\/pre><\/div>\n\n\n\n<p id=\"tw-target-text\">La cl\u00e1usula <em><code>else<\/code><\/em> es opcional (y corresponde a la predeterminada en lenguajes tipo C). Cuando ninguna condici\u00f3n coincide, y no hay m\u00e1s, entonces no pasa nada.<\/p>\n\n\n\n<p id=\"tw-target-text\">Si proviene de lenguajes similares a C y compara esto con la declaraci\u00f3n de cambio en estos lenguajes, notar\u00e1 que no hay fallas autom\u00e1ticas. Esta es una bendici\u00f3n deliberada en Pascal. No es necesario que recuerde colocar las instrucciones de ruptura (<em><code>Break<\/code>)<\/em>. En cada ejecuci\u00f3n, como m\u00e1ximo se ejecuta una rama del caso, eso es todo.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Tipos y conjuntos enumerados, ordinales y matrices de longitud constante<\/h3>\n\n\n\n<p id=\"tw-target-text\">El tipo enumerado en Pascal es un tipo muy agradable y opaco. Probablemente lo usar\u00e1 con mucha m\u00e1s frecuencia que las enumeraciones en otros lenguajes:)<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">type\n  TAnimalKind = (akDuck, akCat, akDog);<\/pre><\/div>\n\n\n\n<p id=\"tw-target-text\">La convenci\u00f3n es prefijar los nombres de enumeraci\u00f3n con un atajo de dos letras de nombre de tipo, por lo tanto, ak = atajo para \u00abAnimal Kind\u00bb. Esta es una convenci\u00f3n \u00fatil, ya que los nombres de enumeraci\u00f3n est\u00e1n en el espacio de nombres de la unidad (global). Entonces, al anteponerles el prefijo ak, minimiza las posibilidades de coincidencia con otros identificadores. <\/p>\n\n\n\n<p id=\"tw-target-text\">Las coincidencias en los nombres no son un problema. Es correcto que diferentes unidades definan el mismo identificador. Pero es una buena idea tratar de evitar las coincidencias de todos modos, para mantener el c\u00f3digo simple de entender.<\/p>\n\n\n\n<p id=\"tw-target-text\">Puede evitar colocar nombres de enumeraci\u00f3n en el espacio de nombres global mediante la directiva del compilador <em><code>{$scopedenums on}<\/code><\/em>. Esto significa que tendr\u00e1 que acceder a ellos calificados por un nombre de tipo, como <code><em>TAnimalKind.akDuck<\/em>.<\/code> La necesidad del prefijo ak desaparece en esta situaci\u00f3n, y probablemente llamar\u00e1s a las enumeraciones Pato, Gato, Perro. Esto es similar a las enumeraciones de C#.<\/p>\n\n\n\n<p id=\"tw-target-text\">El hecho de que el tipo enumerado sea opaco significa que no se puede asignar simplemente a un n\u00famero entero. Sin embargo, para un uso especial, puede usar <em><code>Ord(MyAnimalKind)<\/code><\/em> para convertir forzosamente <em><code>enum<\/code><\/em> a <em><code>int<\/code><\/em>, o <em><code>typecast<\/code><\/em> <em><code>TAnimalKind(MyInteger)<\/code> <\/em>para convertir forzosamente <em><code>int<\/code><\/em> en <em><code>enum<\/code><\/em>. En el \u00faltimo caso, aseg\u00farese de comprobar primero si <em><code>MyInteger<\/code><\/em> est\u00e1 dentro del rango (0 a <em><code>Ord(High(TAnimalKind)<\/code><\/em><\/p>\n\n\n\n<p id=\"tw-target-text\">Los tipos enumerados y ordinales se pueden usar como \u00edndices de matriz:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">type\n  TArrayOfTenStrings = array [0..9] of string;\n  TArrayOfTenStrings1Based = array [1..10] of string;\n\n  TMyNumber = 0..9;\n  TAlsoArrayOfTenStrings = array [TMyNumber] of string;\n\n  TAnimalKind = (akDuck, akCat, akDog);\n  TAnimalNames = array [TAnimalKind] of string;<\/pre><\/div>\n\n\n\n<pre id=\"tw-target-text\" class=\"wp-block-preformatted\">Tambi\u00e9n se pueden usar para crear conjuntos (un campo de bits internamente):<\/pre>\n\n\n\n<p id=\"tw-target-rmn\">Tambi\u00e9n se pueden usar para crear conjuntos (un campo de bits internamente):\n\n<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">type\n  TAnimalKind = (akDuck, akCat, akDog);\n  TAnimals = set of TAnimalKind;\nvar\n  A: TAnimals;\nbegin\n  A := [];\n  A := [akDuck, akCat];\n  A := A + [akDog];\n  A := A * [akCat, akDog];\n  Include(A, akDuck);\n  Exclude(A, akDuck);\nend;<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Bucles (for, while, repeat, for .. in)<\/h3>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\n{$R+} \/\/ comprobaci\u00f3n de rango activada - muy \u00fatil para depurar\nvar\n  MyArray: array [0..9] of Integer;\n  I: Integer;\nbegin\n  \/\/ initialize\n  for I := 0 to 9 do\n    MyArray[I] := I * I;\n\n  \/\/ show\n  for I := 0 to 9 do\n    WriteLn('Square is ', MyArray[I]);\n\n  \/\/ does the same as above\n  for I := Low(MyArray) to High(MyArray) do\n    WriteLn('Square is ', MyArray[I]);\n\n  \/\/ does the same as above\n  I := 0;\n  while I &lt; 10 do\n  begin\n    WriteLn('Square is ', MyArray[I]);\n    I := I + 1; \/\/ or \"I += 1\", or \"Inc(I)\"\n  end;\n\n  \/\/ does the same as above\n  I := 0;\n  repeat\n    WriteLn('Square is ', MyArray[I]);\n    Inc(I);\n  until I = 10;\n\n  \/\/es lo mismo que lo anterior\n  \/\/Nota: Aqu\u00ed enumero los valores de MyArray, no lo indices\n  for I in MyArray do\n    WriteLn('Square is ', I);\nend.<\/pre><\/div>\n\n\n\n<p><strong>Sobre  <code>los bucles repeat<\/code> y <code>while<\/code><\/strong>:<\/p>\n\n\n\n<p>Hay dos diferencias entre estos tipos de bucle: <\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>La condici\u00f3n de bucle tiene un significado opuesto. En mientras.. le dices cuando continuar, pero en repetir.. hasta que le dices cuando parar.<\/li>\n\n\n\n<li>En caso de repetici\u00f3n, la condici\u00f3n no se comprueba al principio. Entonces, el ciclo de repetici\u00f3n siempre se ejecuta al menos una vez.<\/li>\n<\/ol>\n\n\n\n<p id=\"tw-target-text\"><strong>Sobre el bucle <code>for I := \u2026\u200b<\/code><\/strong>:<\/p>\n\n\n\n<p>El <em><code>for I := .. to .. do<\/code><\/em> \u2026\u200b lo construye de manera similar al bucle for tipo C. Sin embargo, est\u00e1 m\u00e1s restringido, ya que no puede especificar acciones\/pruebas arbitrarias para controlar la iteraci\u00f3n del bucle. Esto es estrictamente para iterar sobre n\u00fameros consecutivos (u otros tipos ordinales). La \u00fanica flexibilidad que tiene es que puede usar <em><code>downto<\/code> <\/em>en lugar de <code><em>to<\/em><\/code> para hacer que los n\u00fameros vayan hacia abajo.<\/p>\n\n\n\n<p>A cambio, se ve limpio y est\u00e1 muy optimizado en ejecuci\u00f3n. En particular, las expresiones para el l\u00edmite inferior y superior solo se calculan una vez, antes de que comience el bucle.<\/p>\n\n\n\n<p>Tenga en cuenta que el valor de la variable del contador del ciclo (I en este ejemplo) debe considerarse indefinido despu\u00e9s de que finalice el ciclo, debido a posibles optimizaciones. Acceder al valor de I despu\u00e9s del bucle puede provocar una advertencia del compilador. A menos que salga del ciclo prematuramente con <code><em>Break<\/em><\/code> o <code><em>Exit<\/em><\/code>: en tal caso, se garantiza que la variable contador conservar\u00e1 el \u00faltimo valor.<\/p>\n\n\n\n<p><strong>Sobre el bucle  <code>for I in \u2026\u200b<\/code> <\/strong><\/p>\n\n\n\n<p id=\"tw-target-text\">El <em><code>for I in .. do<\/code><\/em> .. es similar a la construcci\u00f3n <code>foreach<\/code> en muchos lenguajes modernos. Funciona de forma inteligente en muchos tipos integrados:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Puede iterar sobre todos los valores de la matriz (ejemplo anterior).<\/li>\n\n\n\n<li>Puede iterar sobre todos los valores posibles de un tipo enumerado: <\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">var\n  AK: TAnimalKind;\nbegin\n  for AK in TAnimalKind do...<\/pre><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Puede iterar sobre todos los elementos incluidos en el conjunto:<\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">var\n  Animals: TAnimals;\n  AK: TAnimalKind;\nbegin\n  Animals := [akDog, akCat];\n  for AK in Animals do ...<\/pre><\/div>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Y funciona en tipos de listas personalizadas, gen\u00e9ricas o no, como <em>TObjectList <\/em>o <em>TFPGObjectList<\/em>.<\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses\n  SysUtils, FGL;\n\ntype\n  TMyClass = class\n    I, Square: Integer;\n  end;\n  TMyClassList = specialize TFPGObjectList&lt;TMyClass&gt;;\n\nvar\n  List: TMyClassList;\n  C: TMyClass;\n  I: Integer;\nbegin\n  List := TMyClassList.Create(true); \/\/ true = owns children\n  try\n    for I := 0 to 9 do\n    begin\n      C := TMyClass.Create;\n      C.I := I;\n      C.Square := I * I;\n      List.Add(C);\n    end;\n\n    for C in List do\n      WriteLn('Square of ', C.I, ' is ', C.Square);\n  finally\n    FreeAndNil(List);\n  end;\nend.<\/pre><\/div>\n\n\n\n<p id=\"tw-target-text\">Todav\u00eda no explicamos el concepto de clases, por lo que el \u00faltimo ejemplo puede no ser obvio para usted todav\u00eda\u2009\u2014\u2009solo contin\u00fae, tendr\u00e1 sentido m\u00e1s adelante \ud83d\ude42 <\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Salida, Logging<\/h3>\n\n\n\n<p id=\"tw-target-text\">Para simplemente generar cadenas en Pascal, use la rutina <em><code>Write<\/code><\/em> o <em><code>WriteLn<\/code><\/em>. Este \u00faltimo agrega autom\u00e1ticamente una nueva l\u00ednea al final.<\/p>\n\n\n\n<p id=\"tw-target-text\">Esta es una rutina \u00abm\u00e1gica\u00bb en Pascal. Toma un n\u00famero variable de argumentos y pueden ser de cualquier tipo. Todos se convierten en cadenas cuando se muestran, con una sintaxis especial para especificar el relleno y la precisi\u00f3n num\u00e9rica.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">WriteLn('\u00a1Hola Mundo!');\nWriteLn('Se puede mostrar un integer: ', 3 * 4);\nWriteLn('Puedes rellenar un integer: ', 666:10);\nWriteLn('Se puede mostrar un float: ', Pi:1:4);<\/pre><\/div>\n\n\n\n<p id=\"tw-target-text\">Para usar expl\u00edcitamente una nueva l\u00ednea en la cadena, use la constante <em><code>LineEnding<\/code><\/em> (de FPC RTL). (El Castle Game Engine define tambi\u00e9n una constante NL m\u00e1s corta.) Las cadenas de Pascal no interpretan ninguna secuencia especial de barra invertida, por lo que escribir<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">WriteLn('Una l\u00ednea.\\Otra l\u00ednea.'); \/\/ Ejemplo incorrecto<\/pre><\/div>\n\n\n\n<p>no funciona como algunos de ustedes pensar\u00edan. Esto funcionar\u00e1:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">WriteLn('Una l\u00ednea.' + LineEnding + 'Otra l\u00ednea.');<\/pre><\/div>\n\n\n\n<pre id=\"tw-source-rmn\" class=\"wp-block-preformatted\">o solo esto:<\/pre>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">WriteLn('Una l\u00ednea.');\nWriteLn('Otra l\u00ednea.');<\/pre><\/div>\n\n\n\n<p>Tenga en cuenta que esto solo funcionar\u00e1 en aplicaciones de consola. Aseg\u00farese de tener <em><code>{$apptype CONSOLE}<\/code><\/em> (y no <em><code>{$apptype GUI}<\/code><\/em>) definido en su archivo de programa principal. En algunos sistemas operativos en realidad no importa y funcionar\u00e1 siempre (Unix), pero en algunos sistemas operativos intentar escribir algo desde una aplicaci\u00f3n GUI es un error (Windows).<\/p>\n\n\n\n<p id=\"tw-target-text\">En Castle Game Engine: use <em><code>WriteLnLog<\/code><\/em> o <em><code>WriteLnWarning<\/code><\/em>, nunca <em><code>WriteLn<\/code><\/em>, para imprimir informaci\u00f3n de depuraci\u00f3n. Siempre se dirigir\u00e1n a alguna salida \u00fatil. En Unix, salida est\u00e1ndar. En la aplicaci\u00f3n de GUI de Windows, archivo de registro. En Android, la funci\u00f3n de registro de Android (visible cuando usa adb logcat). El uso de <em><code>WriteLn<\/code> <\/em>debe limitarse a los casos en los que escribe una aplicaci\u00f3n de l\u00ednea de comandos (como un convertidor\/generador de modelos 3D) y sabe que la salida est\u00e1ndar est\u00e1 disponible.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Convirtiendo a cadena<\/h3>\n\n\n\n<p id=\"tw-target-text\">Para convertir un n\u00famero arbitrario de argumentos en una cadena (en lugar de generarlos directamente), tiene un par de opciones.<\/p>\n\n\n\n<p id=\"tw-target-text\">Puede convertir tipos particulares en cadenas usando funciones especializadas como <em><code>IntToStr<\/code><\/em> y <em><code>FloatToStr<\/code><\/em>. Adem\u00e1s, puedes concatenar cadenas en Pascal simplemente agreg\u00e1ndolas. Entonces puedes crear una cadena como esta:<em> <code>Mi n\u00famero int es ' + IntToStr(MyInt) + ', y el valor de Pi es ' + FloatToStr(Pi)<\/code>.<\/em><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Ventaja: Absolutamente flexible. Hay muchas versiones sobrecargadas de XxxToStr y amigos (como <em><code>FormatFloat<\/code><\/em>), que cubren muchos tipos. La mayor\u00eda de ellos est\u00e1n en la unidad <em><code>SysUtils<\/code><\/em>.<\/li>\n\n\n\n<li>Otra ventaja: Consistente con las funciones inversas. Para convertir una cadena (por ejemplo, la entrada del usuario) de nuevo en un n\u00famero entero o flotante, use StrToInt, <code><em>StrToFloat<\/em><\/code> y amigos (como <em><code>StrToIntDef<\/code><\/em>).<\/li>\n\n\n\n<li>Desventaja: una concatenaci\u00f3n larga de muchas llamadas y cadenas XxxToStr no se ve bien.<\/li>\n<\/ul>\n\n\n\n<p>La funci\u00f3n <em><code>Format<\/code><\/em>, utilizada como<em> <code>Format('%d %f %s', [MyInt, MyFloat, MyString])<\/code><\/em>. Esto es como la funci\u00f3n <em><code>sprintf<\/code> <\/em>en los lenguajes tipo C. Inserta los argumentos en los marcadores de posici\u00f3n en el patr\u00f3n. Los marcadores de posici\u00f3n pueden usar una sintaxis especial para influir en el formato, <code><em>p. %.4f <\/em><\/code>da como resultado un formato de punto flotante con 4 d\u00edgitos despu\u00e9s del punto decimal.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Ventaja: la separaci\u00f3n de la cadena de patr\u00f3n de los argumentos parece limpia. Si necesita cambiar la cadena del patr\u00f3n sin tocar los argumentos (por ejemplo, al traducir), puede hacerlo f\u00e1cilmente.<\/li>\n\n\n\n<li>Otra ventaja: no hay magia de compilaci\u00f3n. Puede usar la misma sintaxis para pasar cualquier cantidad de argumentos de un tipo arbitrario en sus propias rutinas (declare el par\u00e1metro como una matriz de <em><code>const<\/code><\/em>). Luego puede pasar estos argumentos hacia abajo a Formato, o reconstruir la lista de par\u00e1metros y hacer lo que quiera con ellos.<\/li>\n\n\n\n<li>Desventaja: el compilador no verifica si el patr\u00f3n coincide con los argumentos. El uso de un tipo de marcador de posici\u00f3n incorrecto dar\u00e1 como resultado una excepci\u00f3n en tiempo de ejecuci\u00f3n (excepci\u00f3n <em><code>EConvertError<\/code><\/em>, nada desagradable como un error de segmentaci\u00f3n).<\/li>\n<\/ul>\n\n\n\n<p id=\"tw-target-text\">La rutina <em><code>WriteStr(TargetString, \u2026\u200b)<\/code><\/em> se comporta de manera similar a <code><em>Write(\u2026\u200b)<\/em><\/code>, excepto que el resultado se guarda en <em><code>TargetString<\/code><\/em>. <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Ventaja: admite todas las caracter\u00edsticas de <em><code>Write<\/code><\/em>, incluida la sintaxis especial para formatear como Pi: 1: 4.<\/li>\n\n\n\n<li>Desventaja: la sintaxis especial para formatear es una \u00abmagia del compilador\u00bb, implementada espec\u00edficamente para rutinas como esta. Esto a veces es problem\u00e1tico, por ejemplo. no puede crear su propia rutina <em><code>MyStringFormatter (\u2026)<\/code> <\/em>que tambi\u00e9n permitir\u00eda la sintaxis especial como Pi: 1: 4. Por esta raz\u00f3n (y tambi\u00e9n porque no se implement\u00f3 durante mucho tiempo en los principales compiladores de Pascal), esta construcci\u00f3n no es muy popular.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Unidades (Units)<\/h2>\n\n\n\n<p id=\"tw-target-text\">Las unidades le permiten agrupar cosas comunes (cualquier cosa que se pueda declarar), para que las usen otras unidades y programas. Son equivalentes a m\u00f3dulos y paquetes en otros idiomas. Tienen una secci\u00f3n de interfaz, donde declara lo que est\u00e1 disponible para otras unidades y programas, y luego la implementaci\u00f3n. Guarde la unidad <em>MyUnit<\/em> como <code><em>myunit<\/em>.<em>pas<\/em> <\/code>(en min\u00fasculas con la extensi\u00f3n .pas).<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">$mode objfpc}{$H+}{$J-}\nunit MyUnit;\ninterface\n\nprocedure MyProcedure(const A: Integer);\nfunction MyFunction(const S: string): string;\n\nimplementation\n\nprocedure MyProcedure(const A: Integer);\nbegin\n  WriteLn('A + 10 es: ', A + 10);\nend;\n\nfunction MyFunction(const S: string): string;\nbegin\n  Result := S + 'strings sin gestionadas automaticamente';\nend;\n\nend.<\/pre><\/div>\n\n\n\n<p id=\"tw-target-text\">Los programas finales se guardan como archivos <em><code>myprogram.lpr<\/code><\/em> (lpr = archivo de programa Lazarus; en Delphi usar\u00eda .dpr). Tenga en cuenta que aqu\u00ed son posibles otras convenciones, p. algunos proyectos solo usan .pas para el archivo de programa principal, algunos usan .pp para unidades o programas. Aconsejo usar .pas para unidades y .lpr para programas FPC\/Lazarus. <\/p>\n\n\n\n<p>Un programa puede utilizar una unidad mediante una palabra clave uses:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\n\nprogram MyProgram;\n\nuses\n  MyUnit;\n\nbegin\n  WriteLn(MyFunction('Note: '));\n  MyProcedure(5);\nend.\n<\/pre><\/div>\n\n\n\n<p id=\"tw-target-text\">Una unidad tambi\u00e9n puede contener secciones de inicializaci\u00f3n y finalizaci\u00f3n. Este es el c\u00f3digo que se ejecuta cuando el programa comienza y finaliza.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nunit initialization_finalization;\ninterface\n\nimplementation\n\ninitialization\n  WriteLn('\u00a1Hola Mundo!');\nfinalization\n  WriteLn('\u00a1Adi\u00f3s Mundo!');\nend.<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Unidades que se llaman unas a otras<\/h3>\n\n\n\n<p>Una unidad tambi\u00e9n puede usar otra unidad. Se puede usar otra unidad en la secci\u00f3n de interfaz, o solo en la secci\u00f3n de implementaci\u00f3n. El primero permite definir nuevos identificadores p\u00fablicos  (procedimientos, tipos\u2026) adem\u00e1s de los identificadores de otra unidad. Este \u00faltimo es m\u00e1s limitado (si usa una unidad solo en la secci\u00f3n de implementaci\u00f3n, puede usar sus identificadores solo en la secci\u00f3n implementaci\u00f3n).<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nunit AnotherUnit;\ninterface\n\nuses\n  Classes;\n{\n El tipo \"TComponent\" (clase) es definida en la unidad Classes.\n Es es el motivo porque debemos poner la referencia a la unidad Classes \nal principio de todo\n}\n\nprocedure DoSomethingWithComponent(var C: TComponent);\n\nimplementation\n\nuses SysUtils;\n\nprocedure DoSomethingWithComponent(var C: TComponent);\nbegin\n{ El procedimiento FreeAndNil se define en la unidad SysUtils.\n Ya que solo nos referimos a este procedimiento en la secci\u00f3n implementation, \nes correcto usar la unidad SysUtils en esta secci\u00f3n\n}\n  FreeAndNil(C);\nend;\n\nend.<\/pre><\/div>\n\n\n\n<p>No est\u00e1 permitido tener dependencias de unidades circulares en la interfaz. Es decir, dos unidades no pueden usarse entre s\u00ed en la secci\u00f3n interfaz. La raz\u00f3n es que para \u00abcomprender\u00bb la secci\u00f3n de interfaz de una unidad, el compilador primero debe \u00abcomprender\u00bb todas las unidades que utiliza en la secci\u00f3n de interfaz. El lenguaje Pascal sigue estrictamente esta regla y permite una compilaci\u00f3n r\u00e1pida y una detecci\u00f3n completamente autom\u00e1tica en el lado del compilador de las unidades que se deben volver a compilar. No hay necesidad de usar complicados archivos <em>Makefile<\/em> para una tarea simple de compilaci\u00f3n en Pascal, y no hay necesidad de volver a compilar todo solo para asegurarse de que todas las dependencias se actualicen correctamente.<\/p>\n\n\n\n<p>Se puede hacer una dependencia circular entre unidades cuando al menos una est\u00e1 declarada en la implementaci\u00f3n. Por lo tanto, es correcto que la unidad A use la unidad B en la interfaz y luego la unidad B use la unidad A en la implementaci\u00f3n.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Calificando identificadores con el nombre de unidad<\/h3>\n\n\n\n<p>Diferentes unidades pueden definir el mismo identificador. Para mantener el c\u00f3digo f\u00e1cil de leer y buscar, por lo general debe evitarlo, aunque no siempre es posible. En tales casos, la \u00faltima unidad en la cl\u00e1usula <em>uses<\/em> \u00abgana\u00bb, lo que significa que los identificadores que introducen ocultan a los mismos identificadores introducidos por unidades anteriores.<\/p>\n\n\n\n<p>Siempre puede definir expl\u00edcitamente una unidad de un identificador dado, us\u00e1ndolo como <code><em>MyUnit.MyIdentifier.<\/em><\/code> Esta es la soluci\u00f3n habitual cuando el identificador que desea utilizar desde <em><code>MyUnit<\/code><\/em> est\u00e1 oculto por otra unidad. Por supuesto, tambi\u00e9n puede reorganizar el orden de las unidades en su cl\u00e1usula <em>uses<\/em>, aunque esto puede afectar otras declaraciones adem\u00e1s de la que est\u00e1 tratando de arreglar.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nprogram showcolor;\n\n\n\/\/Ambas unidades, Graphics y GoogleMapsEngine define el tipo TColor;\nuses Graphics, GoogleMapsEngine;\n\nvar\n{Esto funciona tal como esperamos. TColor hace referencia a la \n definici\u00f3n en y GoogleMapsEngine. }\n  \/\/ Color: TColor;\n  { Esto funciona }\n  Color: Graphics.TColor;\nbegin\n  Color := clYellow;\n  WriteLn(Red(Color), ' ', Green(Color), ' ', Blue(Color));\nend.<\/pre><\/div>\n\n\n\n<p id=\"tw-target-text\">En el caso de las unidades, recuerda que tienen dos cl\u00e1usulas <em>Uses<\/em>: una en la interfaz y otra en la implementaci\u00f3n. La regla de que las unidades posteriores ocultan los elementos de las unidades anteriores se aplica aqu\u00ed de forma coherente, lo que significa que las unidades utilizadas en la secci\u00f3n de implementaci\u00f3n pueden ocultar los identificadores de las unidades utilizadas en la secci\u00f3n de interfaz. Sin embargo, recuerde que al leer la secci\u00f3n de la interfaz, solo importan las unidades utilizadas en la interfaz. Esto puede crear una situaci\u00f3n confusa, donde el compilador considera diferentes dos declaraciones aparentemente iguales:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nunit UnitUsingColors;\n\n\/\/ Ejemplo incorrecto\n\ninterface\n\nuses Graphics;\n\nprocedure ShowColor(const Color: TColor);\n\nimplementation\n\nuses GoogleMapsEngine;\n\nprocedure ShowColor(const Color: TColor);\nbegin\n  \/\/ WriteLn(ColorToString(Color));\nend;\n\nend.<\/pre><\/div>\n\n\n\n<p>La unidad <em><code>Graphics<\/code><\/em> (de Lazarus <em>LCL<\/em>) define el tipo de <em><code>TColor<\/code><\/em>. Pero el compilador no podr\u00e1 compilar la unidad anterior, alegando que no implement\u00f3 un procedimiento <em><code>ShowColor<\/code><\/em> que coincida con la declaraci\u00f3n de la interfaz. El problema es que la unidad <em>GoogleMapsEngine<\/em> tambi\u00e9n define un tipo <em><code>TColor<\/code><\/em>. Y se usa solo en la secci\u00f3n de implementaci\u00f3n, por lo tanto, sombrea la definici\u00f3n de <em><code>TColor<\/code><\/em> solo en la implementaci\u00f3n. La versi\u00f3n equivalente de la unidad anterior, donde el error es obvio, se ve as\u00ed:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nunit UnitUsingColors;\n\n\/\/ Ejemplo incorrecto\n\/\/ Esto es lo que el compilador \"ve\" cuando intenta compilar el ejemplo anterior\ninterface\n\nuses Graphics;\n\nprocedure ShowColor(const Color: Graphics.TColor);\n\nimplementation\n\nuses GoogleMapsEngine;\n\nprocedure ShowColor(const Color: GoogleMapsEngine.TColor);\nbegin\n  \/\/ WriteLn(ColorToString(Color));\nend;\n\nend.<\/pre><\/div>\n\n\n\n<p>La soluci\u00f3n es trivial en este caso, simplemente cambie en la implementaci\u00f3n para usar expl\u00edcitamente <em><code>TColor<\/code><\/em> desde la unidad  <em><code>Graphics<\/code><\/em>. Tambi\u00e9n podr\u00eda solucionarlo moviendo  <em><code>GoogleMapsEngine<\/code><\/em>, a la secci\u00f3n de interfaz y antes que <em><code>Graphics<\/code><\/em>, aunque esto podr\u00eda tener otras consecuencias en casos reales, cuando <em><code>UnitUsingColors<\/code><\/em> definir\u00eda m\u00e1s cosas.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nunit UnitUsingColors;\n\ninterface\n\nuses Graphics;\n\nprocedure ShowColor(const Color: TColor);\n\nimplementation\n\nuses GoogleMapsEngine;\n\nprocedure ShowColor(const Color: Graphics.TColor);\nbegin\n  \/\/ WriteLn(ColorToString(Color));\nend;\n\nend.<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Exponer los identificadores de una unidad de otra<\/h3>\n\n\n\n<p>A veces desea usar un identificador de una unidad y exponerlo en una nueva unidad. El resultado final deber\u00eda ser que el uso de la nueva unidad har\u00e1 que el identificador est\u00e9 disponible en el espacio de nombres.<\/p>\n\n\n\n<p>A veces, esto es necesario para preservar la compatibilidad con versiones anteriores de la unidad. A veces es bueno \u00abocultar\u00bb una unidad interna de esta manera.<\/p>\n\n\n\n<p>Esto se puede hacer redefiniendo el identificador en su nueva unidad.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nunit MyUnit;\n\ninterface\n\nuses Graphics;\n\ntype\n  { Expone TColor definido en la unidad Graphics como TMyColor. }\n  TMyColor = TColor;\n\n  { Como alternativa, se expone bajo el mismo nombre, pero haciendo \nreferencia al nombre de la unidad.  \nPodemos referirnos a nosotros mismos con la definici\u00f3n de TColor. }\n\n  TColor = Graphics.TColor;\n\nconst\n  { Esto tambi\u00e9n funciona con constantes. }\n  clYellow = Graphics.clYellow;\n  clBlue = Graphics.clBlue;\n\nimplementation\n\nend.<\/pre><\/div>\n\n\n\n<p>Tenga en cuenta que este truco no se puede hacer tan f\u00e1cilmente con procedimientos, funciones y variables globales. Con procedimientos y funciones, podr\u00eda exponer un puntero constante a un procedimiento en otra unidad (consulte Devoluciones de llamada (tambi\u00e9n conocidas como eventos, tambi\u00e9n conocidas como punteros a funciones, tambi\u00e9n conocidas como variables de procedimiento), pero eso parece bastante enrevesado.<\/p>\n\n\n\n<p>La soluci\u00f3n habitual es entonces crear funciones triviales de \u00abenvoltura\u00bb que debajo simplemente llaman a las funciones desde la unidad interna, pasando los par\u00e1metros y devolviendo valores.<\/p>\n\n\n\n<p>Para que esto funcione con variables globales, se pueden usar propiedades globales (a nivel de unidad), consulte Propiedad.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Clases<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Lo esencial<\/h3>\n\n\n\n<p>En el nivel b\u00e1sico, una clase es solo un contenedor para:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Campos (que es un nombre elegante para \u00abuna variable dentro de una clase\u00bb.<\/li>\n\n\n\n<li>M\u00e9todos (que es un nombre elegante para \u00abun procedimiento o funci\u00f3n dentro de una clase\u00bb.<\/li>\n\n\n\n<li>Propiedades (que es una sintaxis elegante para algo que parece un campo, pero en realidad es un par de m\u00e9todos para obtener y establecer algo; m\u00e1s en Propiedades.<\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">type\n  TMyClass = class\n    MyInt: Integer; \/\/ Esto es un campo\n    property MyIntProperty: Integer read MyInt write MyInt; \/\/ Esto es una propiedad\n    procedure MyMethod; \/\/ Esto es un m\u00e9todo\n  end;\n\nprocedure TMyClass.MyMethod;\nbegin\n  WriteLn(MyInt + 10);\nend;<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"_inheritance_is_as\">Herencia, is, as<\/h3>\n\n\n\n<p>Tenemos herencia y m\u00e9todos virtuales.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nprogram MyProgram;\n\nuses\n  SysUtils;\n\ntype\n  TMyClass = class\n    MyInt: Integer;\n    procedure MyVirtualMethod; virtual;\n  end;\n\n  TMyClassDescendant = class(TMyClass)\n    procedure MyVirtualMethod; override;\n  end;\n\nprocedure TMyClass.MyVirtualMethod;\nbegin\n  WriteLn('TMyClass muestra MyInt + 10: ', MyInt + 10);\nend;\n\nprocedure TMyClassDescendant.MyVirtualMethod;\nbegin\n  WriteLn('TMyClassDescendant muestra MyInt + 20: ', MyInt + 20);\nend;\n\nvar\n  C: TMyClass;\nbegin\n  C := TMyClass.Create;\n  try\n    C.MyVirtualMethod;\n  finally\n    FreeAndNil(C);\n  end;\n\n  C := TMyClassDescendant.Create;\n  try\n    C.MyVirtualMethod;\n  finally\n    FreeAndNil(C);\n  end;\nend.<\/pre><\/div>\n\n\n\n<p>Por defecto los m\u00e9todos no son virtuales, declararlos con <em>virtual <\/em>los hace virtuales. Las anulaciones deben estar marcadas con <em><code>override<\/code><\/em>, de lo contrario recibir\u00e1 una advertencia. Para ocultar un m\u00e9todo sin anularlo (por lo general, no desea hacer esto, a menos que sepa lo que est\u00e1 haciendo), use <code><em>reintroduce<\/em><\/code>.<\/p>\n\n\n\n<p>Para probar la clase de una instancia en tiempo de ejecuci\u00f3n, use el operador <em>is<\/em>. Para encasillar la instancia en una clase espec\u00edfica, use el operador <em>as<\/em>.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">{$mode objfpc}{$H+}{$J-}\nprogram is_as;\n\nuses\n  SysUtils;\n\ntype\n  TMyClass = class\n    procedure MyMethod;\n  end;\n\n  TMyClassDescendant = class(TMyClass)\n    procedure MyMethodInDescendant;\n  end;\n\nprocedure TMyClass.MyMethod;\nbegin\n  WriteLn('MyMethod');\nend;\n\nprocedure TMyClassDescendant.MyMethodInDescendant;\nbegin\n  WriteLn('MyMethodInDescendant');\nend;\n\nvar\n  Descendant: TMyClassDescendant;\n  C: TMyClass;\nbegin\n  Descendant := TMyClassDescendant.Create;\n  try\n    Descendant.MyMethod;\n    Descendant.MyMethodInDescendant;\n\n    { Descendant has all functionality expected of\n      the TMyClass, so this assignment is OK }\n    C := Descendant;\n    C.MyMethod;\n\n    { this cannot work, since TMyClass doesn't define this method }\n    \/\/C.MyMethodInDescendant;\n    if C is TMyClassDescendant then\n      (C as TMyClassDescendant).MyMethodInDescendant;\n\n  finally\n    FreeAndNil(Descendant);\n  end;\nend.<\/pre><\/div>\n\n\n\n<p>En lugar de usar X como <em><code>TMyClass<\/code><\/em>, tambi\u00e9n puede usar <em><code>TMyClass(X)<\/code> <\/em>encasillado sin marcar. Esto es m\u00e1s r\u00e1pido, pero da como resultado un comportamiento indefinido si la X no es, de hecho, un descendiente de <em><code>TMyClass<\/code><\/em>. Por lo tanto, no use el tipo de conversi\u00f3n <em><code>TMyClass(X)<\/code><\/em>, o util\u00edcelo solo en un c\u00f3digo donde es absolutamente obvio que es correcto, por ejemplo, justo despu\u00e9s de probar con <em>is<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">if A is TMyClass then\n  (A as TMyClass).CallSomeMethodOfMyClass;\n\/\/ esto es m\u00e1s r\u00e1pido\nif A is TMyClass then\n    TMyClass(A).CallSomeMethodOfMyClass;<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Propiedades<\/h3>\n\n\n\n<p>Las propiedades son un muy buen \u00abaz\u00facar de sintaxis\u00bb para:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Crear algo que parezca un campo (que se pueda leer y configurar) pero que debajo se realice llamando a m\u00e9todos <em><code>getter<\/code><\/em> y <code><em>setter<\/em><\/code>. El uso t\u00edpico es realizar alg\u00fan efecto secundario (por ejemplo, volver a dibujar la pantalla) cada vez que cambia alg\u00fan valor.<\/li>\n\n\n\n<li>Crear algo que parezca un campo, pero que sea de solo lectura. En efecto, es como una funci\u00f3n constante o sin par\u00e1metros.<\/li>\n<\/ol>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">type\n  TWebPage = class\n  private\n    FURL: string;\n    FColor: TColor;\n    function SetColor(const Value: TColor);\n  public\n    { No hay manrea de ajustar de manera directa.\n     LLame al m\u00e9todo Load, por ejemplo: Load('http:\/\/www.freepascal.org\/'),\n      para cargar una p\u00e1gina y ajustar esta propiedad. }\n    property URL: string read FURL;\n    procedure Load(const AnURL: string);\n    property Color: TColor read FColor write SetColor;\n  end;\n\nprocedure TWebPage.Load(const AnURL: string);\nbegin\n  FURL := AnURL;\n  NetworkingComponent.LoadWebPage(AnURL);\nend;\n\nfunction TWebPage.SetColor(const Value: TColor);\nbegin\n  if FColor &lt;&gt; Value then\n  begin\n    FColor := Value;\n    \/\/ Por ejemplo, produce la actulizaci\u00f3n cada vez que se cambian los valores. value changes\n    Repaint;\n    \/\/Otro ejemplo, aseg\u00farese de que alguna instancia subyacente,\n    \/\/ como un \"RenderingComponent\" (sea lo que sea),\n    \/\/ tiene un valor sincronizado de Color.\n    RenderingComponent.Color := Value;\n  end;\nend;<\/pre><\/div>\n\n\n\n<p>Tenga en cuenta que en lugar de especificar un m\u00e9todo, tambi\u00e9n puede especificar un campo (normalmente un campo privado) para obtener o establecer directamente. En el ejemplo anterior, la propiedad Color utiliza un m\u00e9todo establecido <em><code>SetColor<\/code><\/em>. Pero para obtener el valor, la propiedad <em>Color <\/em>se refiere directamente al campo privado <em><code>FColor<\/code><\/em>. Hacer referencia directa a un campo es m\u00e1s r\u00e1pido que implementar m\u00e9todos <code><em>getter<\/em><\/code> o <code><em>setter<\/em><\/code>  (m\u00e1s r\u00e1pido para usted y m\u00e1s r\u00e1pido en la ejecuci\u00f3n).<\/p>\n\n\n\n<p>Al declarar una propiedad se especifica:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Si se puede leer y c\u00f3mo (leyendo directamente un campo o usando un m\u00e9todo \u00abcaptador\u00bb).<\/li>\n\n\n\n<li>Y, de manera similar, si se puede establecer y c\u00f3mo (escribiendo directamente en un campo designado o llamando a un m\u00e9todo de \u00ab<em><code>setter<\/code><\/em>\u00ab).<\/li>\n<\/ol>\n\n\n\n<p>El compilador verifica que los tipos y par\u00e1metros de los campos y m\u00e9todos indicados coincidan con el tipo de propiedad. Por ejemplo, para leer una propiedad de n\u00famero entero, debe proporcionar un campo de n\u00famero entero o un m\u00e9todo sin par\u00e1metros que devuelva un n\u00famero entero.<\/p>\n\n\n\n<p>T\u00e9cnicamente, para el compilador, los m\u00e9todos \u00ab<em><code>getter<\/code><\/em>\u00bb y \u00ab<em><code>setter<\/code><\/em>\u00bb son simplemente m\u00e9todos normales y pueden hacer absolutamente cualquier cosa (incluidos los efectos secundarios o la aleatorizaci\u00f3n). Pero es una buena convenci\u00f3n dise\u00f1ar propiedades para que se comporten m\u00e1s o menos como campos:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>La funci\u00f3n <em><code>getter<\/code> <\/em>no deber\u00eda tener efectos secundarios visibles (por ejemplo, no deber\u00eda leer alguna entrada del archivo\/teclado). Debe ser determinista (sin aleatorizaci\u00f3n, ni siquiera pseudoaleatorizaci\u00f3n :). Leer una propiedad muchas veces deber\u00eda ser v\u00e1lido y devolver el mismo valor, si nada cambi\u00f3.<\/li>\n<\/ul>\n\n\n\n<p>Tenga en cuenta que est\u00e1 bien que <em><code>getter<\/code> <\/em>tenga alg\u00fan efecto secundario invisible, por ejemplo, almacenar en cach\u00e9 un valor de alg\u00fan c\u00e1lculo (conocido por producir los mismos resultados para una instancia determinada), para devolverlo m\u00e1s r\u00e1pido la pr\u00f3xima vez. <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>De hecho, esta es una de las interesantes posibilidades de una funci\u00f3n \u00ab<em><code>getter<\/code><\/em>\u00ab. La funci\u00f3n <em><code>setter<\/code> <\/em>siempre debe establecer el valor solicitado, de modo que llamar al <em><code>getter<\/code> <\/em>lo devuelva. No rechace valores inv\u00e1lidos en silencio en el \u00ab<em><code>setter<\/code><\/em>\u00bb (provoque una excepci\u00f3n si es necesario). No convierta ni escale el valor solicitado. La idea es que despu\u00e9s de <em><code>MyClass.MyProperty := 123<\/code><\/em>; el programador puede esperar que <code><em>MyClass.MyProperty = 123<\/em>.<\/code><\/li>\n\n\n\n<li>Las propiedades de solo lectura a menudo se usan para hacer que algunos campos sean de solo lectura desde el exterior. Nuevamente, la buena convenci\u00f3n es hacer que se comporte como una constante, al menos constante para esta instancia de objeto con este estado. El valor de la propiedad no debe cambiar inesperadamente. Convi\u00e9rtelo en una funci\u00f3n, no en una propiedad, si su uso tiene un efecto secundario o devuelve algo aleatorio.<\/li>\n\n\n\n<li>El campo de \u00abrespaldo\u00bb de una propiedad es casi siempre privado, ya que la idea de una propiedad es encapsular todo acceso externo a ella.<\/li>\n\n\n\n<li>Es t\u00e9cnicamente posible crear propiedades de solo conjunto, pero a\u00fan no he visto un buen ejemplo de tal cosa \ud83d\ude42<\/li>\n<\/ul>\n\n\n\n<p>Las propiedades tambi\u00e9n se pueden definir fuera de la clase, a nivel de unidad. Entonces, tienen un prop\u00f3sito an\u00e1logo: parecen una variable global, pero est\u00e1n respaldados por rutinas <em><code>getter<\/code> <\/em>y <em><code>setter<\/code><\/em>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Serializacion de propiedades <\/h3>\n\n\n\n<p>Las propiedades publicadas (<em><em><code>Published<\/code><\/em><\/em>) son la base de una serializaci\u00f3n (tambi\u00e9n conocida como componentes de transmisi\u00f3n) en Pascal. La serializaci\u00f3n significa que los datos de la instancia se registran en un flujo (como un archivo), desde el cual se pueden restaurar m\u00e1s tarde.<\/p>\n\n\n\n<p>La serializaci\u00f3n es lo que sucede cuando Lazarus lee (o escribe) el estado del componente desde un archivo xxx.lfm. (En Delphi, el archivo equivalente tiene la extensi\u00f3n .dfm). Tambi\u00e9n puede usar este mecanismo expl\u00edcitamente, usando rutinas como <em><code>ReadComponentFromTextStream<\/code><\/em> de la unidad <em><code>LResources<\/code><\/em>. Tambi\u00e9n puede usar otros algoritmos de serializaci\u00f3n, por ejemplo la  Unidad <em><code>FpJsonRtti<\/code><\/em> (serializar a JSON).<\/p>\n\n\n\n<p>En <strong>Castle Game Engine<\/strong>: use la unidad <em><code>CastleComponentSerialize<\/code><\/em> (basada en <em><code>FpJsonRtti<\/code><\/em>) para serializar nuestras jerarqu\u00edas de interfaz de usuario y componentes de transformaci\u00f3n.<\/p>\n\n\n\n<p>En cada propiedad, puede declarar algunas cosas adicionales que ser\u00e1n \u00fatiles para cualquier algoritmo de serializaci\u00f3n:<\/p>\n\n\n\n<p>Puede especificar el valor predeterminado de la propiedad (usando la palabra clave predeterminada). <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Tenga en cuenta que a\u00fan debe inicializar la propiedad en el constructor a este valor predeterminado exacto (no se hace autom\u00e1ticamente). La declaraci\u00f3n predeterminada es simplemente una informaci\u00f3n para el algoritmo de serializaci\u00f3n: \u00abcuando finaliza el constructor, la propiedad dada tiene el valor dado\u00bb.<\/li>\n\n\n\n<li>Si la propiedad debe almacenarse en absoluto (usando la palabra clave almacenada).<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Excepciones. Un ejemplo r\u00e1pido<\/h3>\n\n\n\n<p>Tenemos excepciones. Se pueden atrapar con cl\u00e1usulas<code><em> try\u2026except\u2026\u200b end<\/em><\/code>, y finalmente tenemos secciones como <code><em>try\u2026finally\u2026end<\/em><\/code>.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">$mode objfpc}{$H+}{$J-}\n\nprogram MyProgram;\n\nuses\n  SysUtils;\n\ntype\n  TMyClass = class\n    procedure MyMethod;\n  end;\n\nprocedure TMyClass.MyMethod;\nbegin\n  if Random &gt; 0.5 then\n    raise Exception.Create('\u00a1Elevando una excepci\u00f3n!');\nend;\n\nvar\n  C: TMyClass;\nbegin\n  Randomize;\n  C := TMyClass.Create;\n  try\n    C.MyMethod;\n  finally\n    FreeAndNil(C);\n  end;\nend.<\/pre><\/div>\n\n\n\n<p>Tenga en cuenta que la cl\u00e1usula <em><code>Finally<\/code> <\/em>se ejecuta incluso si sale del bloque usando <em><code>Exit<\/code> <\/em>(desde la funci\u00f3n\/procedimiento\/m\u00e9todo) o <em><code>Break<\/code> <\/em>o <em><code>Continue<\/code> <\/em>(desde el cuerpo del bucle). <\/p>\n\n\n\n<p>Consulte el cap\u00edtulo <em>Excepciones <\/em>para obtener una descripci\u00f3n m\u00e1s detallada de las excepciones.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Especificadores de visibilidad<\/h3>\n\n\n\n<p>Como en la mayor\u00eda de los lenguajes orientados a objetos, tenemos especificadores de visibilidad para ocultar campos\/m\u00e9todos\/propiedades.<\/p>\n\n\n\n<p>Los niveles b\u00e1sicos de visibilidad son:<\/p>\n\n\n\n<p><em><code>Public<\/code><\/em><\/p>\n\n\n\n<p>todos pueden acceder a \u00e9l, incluido el c\u00f3digo en otras unidades.<\/p>\n\n\n\n<p><code><em>Private<\/em><\/code><\/p>\n\n\n\n<p>s\u00f3lo accesible en esta clase.<\/p>\n\n\n\n<p><code><em>Protected<\/em><\/code><\/p>\n\n\n\n<p>solo accesible en esta clase y descendientes.<\/p>\n\n\n\n<p>La explicaci\u00f3n anterior de visibilidad privada y protegida no es precisamente cierta. El c\u00f3digo en la misma unidad puede superar sus l\u00edmites y acceder libremente a las cosas privadas y protegidas. A veces, esta es una buena caracter\u00edstica, le permite implementar clases estrechamente conectadas. Use <code><em>strict private<\/em><\/code> o <em><code>strict protected<\/code> <\/em>para asegurar sus clases de manera m\u00e1s estricta. Ver <em>Private and strict private<\/em>.<\/p>\n\n\n\n<p>De forma predeterminada, si no especifica la visibilidad, la visibilidad de las cosas declaradas es p\u00fablica. La excepci\u00f3n son las clases compiladas con <em><code>{$M+}<\/code><\/em> o los descendientes de las clases compiladas con <em><code>{$M+}<\/code><\/em>, que incluye todos los descendientes de <em><code>TPersistent<\/code><\/em>, que tambi\u00e9n incluye todos los descendientes de <em>TComponent <\/em>(ya que <em>TComponent <\/em>desciende de <em>TPersistent<\/em>). Para ellos, se publica el especificador de visibilidad predeterminado, que es como p\u00fablico, pero adem\u00e1s el sistema de transmisi\u00f3n sabe manejar esto.<\/p>\n\n\n\n<p>No todos los campos y tipos de propiedades est\u00e1n permitidos en la secci\u00f3n publicada (no todos los tipos se pueden transmitir y solo las clases se pueden transmitir desde campos simples). Solo use p\u00fablico si no le importa la transmisi\u00f3n pero quiere algo disponible para todos los usuarios.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Antecesor por defecto<\/h3>\n\n\n\n<p>Si no declara el tipo antepasado, cada clase hereda de <em><code>TObject<\/code><\/em>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Self<\/h3>\n\n\n\n<p>La palabra clave especial <em><code>Self<\/code> <\/em>se puede usar dentro de la implementaci\u00f3n de la clase para referirse expl\u00edcitamente a su propia instancia. Es equivalente a <em>This<\/em> de C++, Java y lenguajes similares.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Llamando al m\u00e9todo heredado<\/h3>\n\n\n\n<p>Dentro de la implementaci\u00f3n de un m\u00e9todo, si llama a otro m\u00e9todo, por defecto llama al m\u00e9todo de su propia clase. En el c\u00f3digo de ejemplo a continuaci\u00f3n, <code><em>TMyClass2.MyOtherMethod <\/em><\/code>llama a <em><code>MyMethod<\/code><\/em>, que termina llamando a <em><code>TMyClass2.MyMethod.<\/code><\/em><\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses SysUtils;\n\ntype\n  TMyClass1 = class\n    procedure MyMethod;\n  end;\n\n  TMyClass2 = class(TMyClass1)\n    procedure MyMethod;\n    procedure MyOtherMethod;\n  end;\n\nprocedure TMyClass1.MyMethod;\nbegin\n  Writeln('TMyClass1.MyMethod');\nend;\n\nprocedure TMyClass2.MyMethod;\nbegin\n  Writeln('TMyClass2.MyMethod');\nend;\n\nprocedure TMyClass2.MyOtherMethod;\nbegin\n  MyMethod; \/\/ esto llama a TMyClass2.MyMethod\nend;\n\nvar\n  C: TMyClass2;\nbegin\n  C := TMyClass2.Create;\n  try\n    C.MyOtherMethod;\n  finally FreeAndNil(C) end;\nend.<\/pre><\/div>\n\n\n\n<p>Si el m\u00e9todo no est\u00e1 definido en una clase determinada, llama al m\u00e9todo de una clase antepasada. En efecto, cuando llama a <em><code>MyMethod<\/code> <\/em>en una instancia de TMyClass2, entonces:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>El compilador busca <em><code>TMyClass2.MyMethod<\/code><\/em><\/li>\n\n\n\n<li>Si no lo encuentra, busca <em><code>TMyClass1.MyMethod<\/code><\/em>.<\/li>\n\n\n\n<li>Si no lo encuentra, busca <em><code>TObject.MyMethod<\/code><\/em>.<\/li>\n\n\n\n<li>si no se encuentra, la compilaci\u00f3n falla. <\/li>\n<\/ul>\n\n\n\n<p>Puede probarlo comentando la definici\u00f3n de <code><em>TMyClass2.MyMethod <\/em><\/code>en el ejemplo anterior. En efecto, <em><code>TMyClass1.MyMethod <\/code><\/em>ser\u00e1 llamado por <code><em>TMyClass2.MyOtherMethod.<\/em><\/code><\/p>\n\n\n\n<p>A veces, no desea llamar al m\u00e9todo de su propia clase. Desea llamar al m\u00e9todo de un antepasado (o al antepasado de un antepasado, etc.). Para hacer esto, agregue la palabra clave heredada antes de la llamada a <em><code>MyMethod<\/code><\/em>, as\u00ed:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">inherited MyMethod;<\/pre><\/div>\n\n\n\n<p>De esta forma, fuerza al compilador a comenzar a buscar desde una clase antecesora. En nuestro ejemplo, significa que el compilador est\u00e1 buscando <em><code>MyMethod<\/code><\/em> dentro de <em><code>TMyClass1.MyMethod<\/code><\/em>, luego <em><code>TObject.MyMethod<\/code><\/em> y luego se da por vencido. Ni siquiera considera usar la implementaci\u00f3n de <em><code>TMyClass2.MyMethod<\/code><\/em>.<\/p>\n\n\n\n<p>Consejo:  a delante, cambie la implementaci\u00f3n de <em><code>TMyClass2.MyOtherMethod<\/code><\/em> anterior para usar <code><em>MyMethod<\/em><\/code> heredado y vea la diferencia en el resultado.<\/p>\n\n\n\n<p>La llamada heredada se usa a menudo para llamar al m\u00e9todo antecesor del mismo nombre. De esta forma, los descendientes pueden mejorar a los ancestros (manteniendo la funcionalidad del ancestro, en lugar de reemplazar la funcionalidad del ancestro). Como en el ejemplo de abajo.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses SysUtils;\n\ntype\n  TMyClass1 = class\n    constructor Create;\n    procedure MyMethod(const A: Integer);\n  end;\n\n  TMyClass2 = class(TMyClass1)\n    constructor Create;\n    procedure MyMethod(const A: Integer);\n  end;\n\nconstructor TMyClass1.Create;\nbegin\n  inherited Create; \/\/ esto llama a TObject.Create\n  Writeln('TMyClass1.Create');\nend;\n\nprocedure TMyClass1.MyMethod(const A: Integer);\nbegin\n  Writeln('TMyClass1.MyMethod ', A);\nend;\n\nconstructor TMyClass2.Create;\nbegin\n  inherited Create; \/\/ this calls TMyClass1.Create\n  Writeln('TMyClass2.Create');\nend;\n\nprocedure TMyClass2.MyMethod(const A: Integer);\nbegin\n  inherited MyMethod(A); \/\/ this calls TMyClass1.MyMethod\n  Writeln('TMyClass2.MyMethod ', A);\nend;\n\nvar\n  C: TMyClass2;\nbegin\n  C := TMyClass2.Create;\n  try\n    C.MyMethod(123);\n  finally FreeAndNil(C) end;\nend.<\/pre><\/div>\n\n\n\n<p>Dado que el uso <code><em>inherited<\/em><\/code> para llamar a un m\u00e9todo con el mismo nombre, con los mismos argumentos, es un caso muy frecuente, hay un atajo especial para ello: puede escribir <code><em>inherited<\/em><\/code> ; (palabra clave heredada seguida inmediatamente por un punto y coma, en lugar de un nombre de m\u00e9todo). Esto significa \u00abllamar a un m\u00e9todo heredado con el mismo nombre, pas\u00e1ndole los mismos argumentos que el m\u00e9todo actual\u00bb.<\/p>\n\n\n\n<p>Consejo: En el ejemplo anterior, todos los <code><em>inherited<\/em><\/code>\u2026\u200b; las llamadas podr\u00edan ser reemplazadas por un simple <code><em>inherited<\/em><\/code>.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">procedure TMyClass2.MyMethod(A: Integer);\nbegin\n  Writeln('TMyClass2.MyMethod beginning ', A);\n  A := 456;\n  { This calls TMyClass1.MyMethod with A = 456,\n    regardless of the A value passed to this method (TMyClass2.MyMethod). }\n  inherited;\n  Writeln('TMyClass2.MyMethod ending ', A);\nend;<\/pre><\/div>\n\n\n\n<p>Nota 2: por lo general, desea que <em><code>MyMethod<\/code> <\/em>sea virtual cuando muchas clases (a lo largo de la \u00abcadena de herencia\u00bb) lo definen. M\u00e1s sobre los m\u00e9todos virtuales en la secci\u00f3n a continuaci\u00f3n. Pero la palabra clave heredada funciona independientemente de si el m\u00e9todo es virtual o no. El heredado siempre significa que el compilador comienza a buscar el m\u00e9todo en un ancestro, y tiene sentido tanto para los m\u00e9todos virtuales como para los no virtuales.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">M\u00e9todos virtuales, anular y reintroducir<\/h3>\n\n\n\n<p>Por defecto, los m\u00e9todos no son virtuales. Esto es similar a C++ y diferente a Java.<\/p>\n\n\n\n<p>Cuando un m\u00e9todo no es virtual, el compilador determina a qu\u00e9 m\u00e9todo llamar seg\u00fan el tipo de clase declarado actualmente, no seg\u00fan el tipo de clase realmente creado. La diferencia parece sutil, pero es importante cuando se declara que su variable tiene una clase como <em><code>TFruit<\/code><\/em>, pero de hecho puede ser una clase descendiente como <em><code>TApple<\/code><\/em>.<\/p>\n\n\n\n<p>La idea de la programaci\u00f3n orientada a objetos es que la clase descendiente siempre es tan buena como el antepasado, por lo que el compilador permite usar una clase descendiente siempre que se espera el antepasado. Cuando tu m\u00e9todo no es virtual, esto puede tener consecuencias no deseadas. Considere el siguiente ejemplo:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses SysUtils;\n\ntype\n  TFruit = class\n    procedure Eat;\n  end;\n\n  TApple = class(TFruit)\n    procedure Eat;\n  end;\n\nprocedure TFruit.Eat;\nbegin\n  Writeln('Comiendo fruta');\nend;\n\nprocedure TApple.Eat;\nbegin\n  Writeln('Comiendo un manzana');\nend;\n\nprocedure DoSomethingWithAFruit(const Fruit: TFruit);\nbegin\n  Writeln('We have a fruit with class ', Fruit.ClassName);\n  Writeln('We eat it:');\n  Fruit.Eat;\nend;\n\nvar\n  Apple: TApple; \/\/ Nota: podr\u00edas declrar \"Apple: TFruit\" aqu\u00ed\nbegin\n  Apple := TApple.Create;\n  try\n    DoSomethingWithAFruit(Apple);\n  finally FreeAndNil(Apple) end;\nend.<\/pre><\/div>\n\n\n\n<p>Este ejemplo mostrar\u00e1<\/p>\n\n\n\n<div class=\"wp-block-group\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<p>We have a fruit with class TApple<\/p>\n\n\n\n<p> We eat it: <\/p>\n\n\n\n<p>Eating a fruit<\/p>\n\n\n\n<p>En efecto, la llamada <em><code>Fruit.Eat<\/code><\/em> llam\u00f3 a la implementaci\u00f3n <code><em>TFruit.Eat<\/em> <\/code>y nada llam\u00f3 a la implementaci\u00f3n <em><code>TApple.Eat<\/code><\/em>. <\/p>\n\n\n\n<p>Si piensa en c\u00f3mo funciona el compilador, esto es natural: cuando escribi\u00f3<code><em> Fruit.Eat<\/em><\/code>, se declar\u00f3 que la variable <em><code>Fruit<\/code> <\/em>conten\u00eda una clase <em><code>TFruit<\/code><\/em>. Entonces, el compilador estaba buscando el m\u00e9todo llamado <em><code>Eat<\/code> <\/em>dentro de la clase <em><code>TFruit<\/code><\/em>. Si la clase <em><code>TFruit<\/code> <\/em>no contuviera dicho m\u00e9todo, el compilador buscar\u00eda dentro de un ancestro (<em><code>TObject<\/code> <\/em>en este caso). Pero el compilador no puede buscar dentro de los descendientes (como <em><code>TApple<\/code><\/em>), ya que no sabe si la clase real de <em><code>Fruit<\/code> <\/em>es <em><code>TApple<\/code><\/em>, <em><code>TFruit<\/code> <\/em>o alg\u00fan otro descendiente de <em><code>TFruit<\/code> <\/em>(como <em><code>TOrange<\/code><\/em>, que no se muestra en el ejemplo anterior).<\/p>\n\n\n\n<p>En otras palabras, el m\u00e9todo a llamar se determina en tiempo de compilaci\u00f3n.<\/p>\n\n\n\n<p>El uso de los m\u00e9todos virtuales cambia este comportamiento. Si el m\u00e9todo <em><code>Eat<\/code> <\/em>fuera virtual (a continuaci\u00f3n se muestra un ejemplo), la implementaci\u00f3n real que se llamar\u00e1 se determina en tiempo de ejecuci\u00f3n. Si la variable <em><code>Fruit<\/code> <\/em>contiene una instancia de la clase <em><code>TApple<\/code> <\/em>(incluso si se declara como <em><code>TFruit<\/code><\/em>), el m\u00e9todo <em><code>Eat<\/code> <\/em>se buscar\u00e1 primero dentro de la clase <em><code>TApple<\/code><\/em>. <\/p>\n\n\n\n<p>En Object Pascal, para definir un m\u00e9todo como virtual, necesita:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Marque su primera definici\u00f3n (en el ancestro m\u00e1s alto) con la palabra clave <em>virtual<\/em>.<\/li>\n\n\n\n<li>Marque todas las dem\u00e1s definiciones (en los descendientes) con la palabra clave <em><code>override<\/code><\/em>. Todas las versiones anuladas deben tener exactamente los mismos par\u00e1metros (y devolver los mismos tipos, en el caso de las funciones).<\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses SysUtils;\n\ntype\n  TFruit = class\n    procedure Eat; virtual;\n  end;\n\n  TApple = class(TFruit)\n    procedure Eat; override;\n  end;\n\nprocedure TFruit.Eat;\nbegin\n  Writeln('Eating a fruit');\nend;\n\nprocedure TApple.Eat;\nbegin\n  Writeln('Eating an apple');\nend;\n\nprocedure DoSomethingWithAFruit(const Fruit: TFruit);\nbegin\n  Writeln('We have a fruit with class ', Fruit.ClassName);\n  Writeln('We eat it:');\n  Fruit.Eat;\nend;\n\nvar\n  Apple: TApple; \/\/ Note: you could as well declare \"Apple: TFruit\" here\nbegin\n  Apple := TApple.Create;\n  try\n    DoSomethingWithAFruit(Apple);\n  finally FreeAndNil(Apple) end;\nend.\n\n<\/pre><\/div>\n\n\n\n<p>Este ejemplo mostrar\u00e1<\/p>\n\n\n\n<div class=\"wp-block-group\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<p>We have a fruit with class<\/p>\n\n\n\n<p> TApple We eat it: <\/p>\n\n\n\n<p>Eating an apple<\/p>\n\n\n\n<p>Internamente, los m\u00e9todos virtuales funcionan al tener la llamada tabla de m\u00e9todos virtuales asociada con cada clase. Esta tabla es una lista de punteros a las implementaciones de m\u00e9todos virtuales para esta clase. Al llamar al m\u00e9todo <em><code>Eat<\/code><\/em>, el compilador busca en una tabla de m\u00e9todo virtual asociada con la clase real de <code><em>Fruit<\/em><\/code> y usa un puntero a la implementaci\u00f3n de Eat almacenada all\u00ed.<\/p>\n\n\n\n<p>Si no usa la palabra clave <code><em>override<\/em><\/code>, el compilador le advertir\u00e1 que est\u00e1 ocultando (oscureciendo) el m\u00e9todo virtual de un ancestro con una definici\u00f3n no virtual. Si est\u00e1 seguro de que esto es lo que desea, puede agregar una palabra clave de reintroducci\u00f3n. Pero en la mayor\u00eda de los casos, preferir\u00e1 mantener el m\u00e9todo virtual y agregar la palabra clave anular, asegur\u00e1ndose as\u00ed de que siempre se invoque correctamente.<\/p>\n<\/div><\/div>\n<\/div><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Liberando las clases<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Recuerde liberar todas las instancias de las clases<\/h3>\n\n\n\n<p>Las instancias de clase deben liberarse manualmente, de lo contrario, se producen p\u00e9rdidas de memoria. Recomiendo usar las opciones del compilador:  <code><em>-gl -gh,<\/em><\/code> para detectar fugas de memoria (ver <a rel=\"noreferrer noopener\" href=\"https:\/\/castle-engine.io\/manual_optimization.php#section_memory\" target=\"_blank\">https:\/\/castle-engine.io\/manual_optimization.php#section_memory<\/a>).<\/p>\n\n\n\n<p>Tenga en cuenta que esto no se refiere a las excepciones planteadas. Aunque crees una clase cuando generas una excepci\u00f3n (y es una clase perfectamente normal, y tambi\u00e9n puedes crear tus propias clases para este prop\u00f3sito). Pero este la instancia de este tipo de clase se libera autom\u00e1ticamente. La  instancia de este tipo de clase se libera autom\u00e1ticamente.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u00bfC\u00f3mo liberar?<\/h3>\n\n\n\n<p>Para liberar la instancia de una clase, es mejor llamar a <em><code>FreeAndNil(A)<\/code><\/em> desde la unidad <em><code>SysUtils<\/code><\/em>. Este procedimiento comprueba si A es <code><em>nil<\/em><\/code>, si no, llama a su destructor y establece A en <code><em>nil<\/em><\/code>. Entonces llamarlo muchas veces seguidas y no ser\u00eda un error.<\/p>\n\n\n\n<p>Es m\u00e1s o menos un atajo para<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">if A &lt;&gt; nil then\nbegin\n  A.Destroy;\n  A := nil;\nend;<\/pre><\/div>\n\n\n\n<p>En realidad, eso es una simplificaci\u00f3n excesiva, ya que <em><code>FreeAndNil<\/code><\/em> hace un truco \u00fatil y establece la variable A en <em><code>nil<\/code><\/em> antes de llamar al destructor. Esto ayuda a prevenir cierta clase de errores\u2009\u2014\u2009la idea es que el c\u00f3digo \u00abexterno\u00bb nunca deber\u00eda acceder a una instancia de la clase a medio destruir.<\/p>\n\n\n\n<p>A menudo, tambi\u00e9n ver\u00e1 personas que usan el m\u00e9todo <em><code>A.Free<\/code><\/em>, que es como hacer<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">if A &lt;&gt; nil then\n  A.Destroy;<\/pre><\/div>\n\n\n\n<p>Esto libera  A, a menos que sea <em><code>nil<\/code><\/em>. Tenga en cuenta que, en circunstancias normales, nunca debe llamar a un m\u00e9todo de una instancia que puede ser <em><code>nil<\/code><\/em>. Entonces, la llamada <code><em>A.Free <\/em><\/code>puede parecer sospechosa a primera vista, si A puede ser <em><code>nil<\/code><\/em>. Sin embargo, el m\u00e9todo <em><code>Free<\/code><\/em> es una excepci\u00f3n a esta regla. Hace un truquillo en la implementaci\u00f3n, es decir, comprueba si <em><code>Self &lt;&gt; nil.<\/code><\/em><\/p>\n\n\n\n<p>Nota: Este truquillo  (permitir oficialmente que el m\u00e9todo se use con <em><code>Self = nil<\/code><\/em>) solo es posible para m\u00e9todos no virtuales. Y siempre que <code><em>Self = nil <\/em><\/code>sea posible, el m\u00e9todo no puede llamar a ning\u00fan m\u00e9todo virtual ni acceder a ning\u00fan campo, ya que estos se bloquear\u00edan con una violaci\u00f3n de acceso cuando se llamara a un puntero nulo. Consulte el c\u00f3digo de ejemplo <em><a href=\"https:\/\/github.com\/michaliskambi\/modern-pascal-introduction\/blob\/master\/code-samples\/method_with_self_nil.lpr\">method_with_self_nil.lpr<\/a><\/em>. No recomendamos usar este truco en su propio c\u00f3digo (para m\u00e9todos virtuales o no virtuales), ya que es contrario a la intuici\u00f3n del uso normal; en general, todos los m\u00e9todos de instancia deber\u00edan poder asumir que funcionan en una instancia v\u00e1lida (no nula). y puede acceder a los campos y llamar a cualquier otro m\u00e9todo (virtual o no).<\/p>\n\n\n\n<p>Aconsejo usar<em><code> FreeAndNil(A) <\/code><\/em>siempre, sin excepciones, y nunca llamar directamente al m\u00e9todo <em><code>Free<\/code><\/em> o <em><code>Destroy<\/code><\/em> destructor. Castle Game Engine lo hace as\u00ed. Ayuda mantener una buena afirmaci\u00f3n de que todas las referencias son nulas o apuntan a instancias v\u00e1lidas.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Liberaci\u00f3n manual y autom\u00e1tica<\/h3>\n\n\n\n<p>En muchas situaciones, la necesidad de liberar la instancia no es un gran problema. Simplemente escribe un destructor, que coincide con un constructor, y libere todo lo que se asign\u00f3 en el constructor (o, m\u00e1s completamente, en toda la vida \u00fatil de la clase). Tenga cuidado de liberar cada cosa solo una vez. Por lo general, es una buena idea establecer la referencia liberada en <em><code>nil<\/code><\/em>, por lo general, es m\u00e1s c\u00f3modo hacerlo llamando a <em><code>FreeAndNil(A)<\/code>.<\/em><\/p>\n\n\n\n<p>Entonces, ser\u00eda algo as\u00ed:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">uses SysUtils;\n\ntype\n  TGun = class\n  end;\n\n  TPlayer = class\n    Gun1, Gun2: TGun;\n    constructor Create;\n    destructor Destroy; override;\n  end;\n\nconstructor TPlayer.Create;\nbegin\n  inherited;\n  Gun1 := TGun.Create;\n  Gun2 := TGun.Create;\nend;\n\ndestructor TPlayer.Destroy;\nbegin\n  FreeAndNil(Gun1);\n  FreeAndNil(Gun2);\n  inherited;\nend;<\/pre><\/div>\n\n\n\n<p>Para evitar la necesidad de liberar expl\u00edcitamente la instancia, tambi\u00e9n se puede usar la  <em><code>TComponent<\/code><\/em> como propietario. Un objeto que sea de su propiedad ser\u00e1 liberado autom\u00e1ticamente por el propietario. El mecanismo es inteligente y nunca liberar\u00e1 una instancia ya liberada (por lo que las cosas tambi\u00e9n funcionar\u00e1n correctamente si libera manualmente el objeto que posee antes). Podemos cambiar el ejemplo anterior por este:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">uses SysUtils, Classes;\n\ntype\n  TGun = class(TComponent)\n  end;\n\n  TPlayer = class(TComponent)\n    Gun1, Gun2: TGun;\n    constructor Create(AOwner: TComponent); override;\n  end;\n\nconstructor TPlayer.Create(AOwner: TComponent);\nbegin\n  inherited;\n  Gun1 := TGun.Create(Self);\n  Gun2 := TGun.Create(Self);\nend;<\/pre><\/div>\n\n\n\n<p>Tenga en cuenta que necesitamos anular el constructor virtual de <em><code>TComponent<\/code><\/em> en este caso. Entonces no podemos cambiar los par\u00e1metros del constructor. (En realidad, puede\u2009\u2014\u2009declarar un nuevo constructor con <em>overload<\/em>. Pero tenga cuidado, ya que algunas funcionalidades, por ejemplo, la herencia, a\u00fan usar\u00e1n el constructor virtual, as\u00ed que aseg\u00farese de que funcione correctamente en cualquier caso).<\/p>\n\n\n\n<p>Tenga en cuenta que siempre puede usar un valor nulo para como propietario. De esta forma, el mecanismo de \u00abpropiedad\u00bb no se utilizar\u00e1 para este componente. Tiene sentido si necesita usar el descendiente de <em><code>TComponent<\/code><\/em>, pero siempre que desee liberarlo manualmente. Para ello, crear\u00eda un componente descendiente como este: <em><code>ManualGun := TGun.Create(nil);.<\/code><\/em><\/p>\n\n\n\n<p>Otro mecanismo para la liberaci\u00f3n autom\u00e1tica es la funcionalidad <em><code>OwnsObjects<\/code><\/em> (\u00a1por defecto ya es verdad!) de clases  como <em><code>TFPGObjectList<\/code><\/em> o <em><code>TObjectList<\/code><\/em>. Entonces  podemos escribir:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">uses SysUtils, Classes, FGL;\n\ntype\n  TGun = class\n  end;\n\n  TGunList = specialize TFPGObjectList&lt;TGun&gt;;\n\n  TPlayer = class\n    Guns: TGunList;\n    Gun1, Gun2: TGun;\n    constructor Create;\n    destructor Destroy; override;\n  end;\n\nconstructor TPlayer.Create;\nbegin\n    inherited;\n    \/\/Actualmente el par\u00e1metro OwnsObjects por defecto vale true\n  Guns := TGunList.Create(true);\n  Gun1 := TGun.Create;\n  Guns.Add(Gun1);\n  Gun2 := TGun.Create;\n  Guns.Add(Gun2);\nend;\n\ndestructor TPlayer.Destroy;\nbegin\n    {Debemos tener cuidad al liberar la lista\n    Ya que se liberara automaticamente su contenido}\n    FreeAndNil(Guns);\n\n  {No es necesario liberar Gun1, Gun2. Aunque es un buena h\u00e1bito igualarlos a Nil\n  De esta manera sabemos que est\u00e1n liberados. En esta simple clase, con un destructor sencillo\n  es obvio que no vamos a acceder de nuevo. Pero hacer esto vale la pena en el caso de destructores m\u00e1s \n  complejos.\n  Como alternativa, podemos evitar declarar Gun1 y Gun2,\n  y en su lugar usar Guna[0] y Gun[a1] en su propio c\u00f3digo. \n  O crear un m\u00e9todo llamado Gun1 que devuelva Guns[0].\n\n  Gun1 := nil;\n  Gun2 := nil;\n  inherited;\nend;<\/pre><\/div>\n\n\n\n<p>Tenga en cuenta que el mecanismo de \u00abpropiedad\u00bb de las clases de lista es simple y obtendr\u00e1 un error si libera la instancia utilizando otros medios. Utilice el m\u00e9todo <em>Extract<\/em> para eliminar algo de una lista sin liberarlo, asumiendo as\u00ed la responsabilidad de liberarlo usted mismo.<\/p>\n\n\n\n<p>En Castle Game Engine, los descendientes de <em>TX3DNode<\/em> tienen administraci\u00f3n de memoria autom\u00e1tica cuando se insertan como hijos de otro TX3DNode. El nodo ra\u00edz <em>X3D<\/em>, <em>TX3DRootNode<\/em>, a su vez, suele ser propiedad de <em><code>TCastleSceneCore<\/code><\/em>. Algunas otras elementos tambi\u00e9n tienen un mecanismo de propiedad simple: busque par\u00e1metros y propiedades llamados <em>OwnsXxx<\/em>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">El destructor virtual llamado Destroy<\/h3>\n\n\n\n<p>Como viste en los ejemplos anteriores, cuando se destruye la clase, se llama a su destructor llamado <em><code>Destroy<\/code><\/em>.<\/p>\n\n\n\n<p>En teor\u00eda, podr\u00eda tener m\u00faltiples destructores, pero en la pr\u00e1ctica casi nunca es una buena idea. Es mucho m\u00e1s f\u00e1cil tener un solo destructor llamado <em><code>Destroy<\/code><\/em>, que a su vez es llamado por el m\u00e9todo <em><code>Free<\/code><\/em>, que a su vez es llamado por el procedimiento <em><code>FreeAndNil<\/code><\/em>.<\/p>\n\n\n\n<p>El destructor <em><code>Destroy<\/code><\/em> en <em><code>TObject<\/code><\/em> se define como un m\u00e9todo virtual, por lo que siempre debe marcarlo con la palabra clave <em><code>override<\/code><\/em> en todas sus clases (ya que todas las clases descienden de <em><code>TObject<\/code><\/em>). Esto hace que el m\u00e9todo <em><code>Free<\/code><\/em> funcione correctamente. Recuerde c\u00f3mo funcionan los m\u00e9todos virtuales a partir de m\u00e9todos virtuales, anular y volver a introducir.<\/p>\n\n\n\n<p>Nota: Esta informaci\u00f3n sobre los destructores es, de hecho, inconsistente con los constructores.<\/p>\n\n\n\n<p>Es normal que una clase tenga m\u00faltiples constructores. Por lo general, todos se llaman <em><code>Create<\/code><\/em> y solo tienen diferentes par\u00e1metros, pero tambi\u00e9n est\u00e1 bien inventar otros nombres para los constructores.<\/p>\n\n\n\n<p>Adem\u00e1s, el constructor <em><code>Create<\/code><\/em> en <em><code>TObject<\/code><\/em> no es virtual, por lo que no lo marca con anulado en los descendientes.<\/p>\n\n\n\n<p>Todo esto le brinda un poco de flexibilidad adicional al definir constructores. A menudo no es necesario hacerlos virtuales, por lo que, de forma predeterminada, no est\u00e1 obligado a hacerlo.<\/p>\n\n\n\n<p>Tenga en cuenta, sin embargo, que esto cambia para los descendientes de <em><code>TComponent<\/code><\/em>. El <em><code>TComponent<\/code><\/em> define un constructor virtual <em><code>Create(AOwner: TComponent)<\/code><\/em>. Necesita un constructor virtual para que funcione el sistema de herencia. Al definir los descendientes del <em><code>TComponent<\/code><\/em>, debe anular este constructor (y marcarlo con la palabra clave <em><code>override<\/code><\/em>) y realizar toda su inicializaci\u00f3n dentro de \u00e9l. Tambi\u00e9n est\u00e1 bien definir constructores adicionales, pero solo deben actuar como \u00abayudantes\u00bb. La instancia siempre deber\u00eda funcionar cuando se crea con el constructor <em><code>Create(AOwner: TComponent)<\/code><\/em>; de lo contrario, no se construir\u00e1 correctamente durante la transmisi\u00f3n (<em>streaming<\/em>). La transmisi\u00f3n  utiliza, por ejemplo al guardar y cargar este componente en un formulario de Lazarus.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Notificaci\u00f3n de liberaci\u00f3n<\/h3>\n\n\n\n<p>Si copia una referencia a la instancia, de modo que tiene dos referencias a la misma en memoria, y luego una de ellas se libera, la otra se convierte en un \u00abpuntero huerfano\u00bb. No se debe acceder a este, ya que apunta a una memoria que ya no est\u00e1 asignada. Acceder a \u00e9l puede resultar en un error de tiempo de ejecuci\u00f3n, o que se devuelva basura (ya que la memoria puede reutilizarse para otras cosas en su programa).<\/p>\n\n\n\n<p>Usar <em><code>FreeAndNil<\/code><\/em> para liberar la instancia no ayuda aqu\u00ed. <em><code>FreeAndNil<\/code><\/em> establece en cero solo la referencia que obtuvo, no hay forma de que establezca todas las dem\u00e1s referencias autom\u00e1ticamente. Considere este c\u00f3digo:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">var\n  Obj1, Obj2: TObject;\nbegin\n  Obj1 := TObject.Create;\n  Obj2 := Obj1;\n  FreeAndNil(Obj1);\n\n  \/\/ what happens if we access Obj1 or Obj2 here?\nend;<\/pre><\/div>\n\n\n\n<p>Al final de este bloque, el <em><code>Obj1<\/code><\/em> es nulo. Si alg\u00fan c\u00f3digo tiene que acceder a \u00e9l, puede usar de manera confiable si <em><code>Obj1 &lt;&gt; nil<\/code><\/em> entonces&#8230; para evitar llamar a m\u00e9todos en una instancia liberada, como<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">if Obj1 &lt;&gt; nil then\n  WriteLn(Obj1.ClassName);<\/pre><\/div>\n\n\n\n<p>Intentar acceder a un campo de una instancia nula da como resultado una excepci\u00f3n predecible en tiempo de ejecuci\u00f3n.<\/p>\n\n\n\n<p>Entonces, incluso si alg\u00fan c\u00f3digo no verificar\u00e1 <code>Obj1 &lt;&gt; nil<\/code>, y acceder\u00e1 ciegamente al campo <em><code>Obj1<\/code><\/em>, obtendr\u00e1 una excepci\u00f3n en tiempo de ejecuci\u00f3n. Lo mismo ocurre con llamar a un m\u00e9todo virtual o llamar a un m\u00e9todo no virtual que accedi\u00f3 a un campo de una instancia nula. <\/p>\n\n\n\n<p>Con <em><code>Obj2<\/code><\/em>, las cosas son menos predecibles. No es nulo, pero no es v\u00e1lido. Intentar acceder a un campo de una instancia no v\u00e1lida no nula da como resultado un comportamiento impredecible\u2009\u2014\u2009tal vez una excepci\u00f3n de violaci\u00f3n de acceso, tal vez una devoluci\u00f3n de datos basura.<\/p>\n\n\n\n<p>Hay varias soluciones para ello:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Una soluci\u00f3n es tener buen cuidado y leer la documentaci\u00f3n. No suponga nada sobre la vida \u00fatil de la referencia, si se crea mediante otro c\u00f3digo. Si una clase <em><code>TCar<\/code><\/em> tiene un campo que apunta a alguna instancia de <em><code>TWheel<\/code><\/em>, es una convenci\u00f3n que la referencia a la rueda sea v\u00e1lida mientras exista la referencia al autom\u00f3vil, y el autom\u00f3vil liberar\u00e1 sus ruedas dentro de su destructor. Pero eso es solo una convenci\u00f3n, la documentaci\u00f3n debe mencionar si est\u00e1 sucediendo algo m\u00e1s complicado.<\/li>\n\n\n\n<li>En el ejemplo anterior, justo despu\u00e9s de liberar la instancia de <em><code>Obj1<\/code><\/em>, simplemente puede configurar la variable <em><code>Obj2<\/code><\/em> expl\u00edcitamente en <em><code>nil<\/code><\/em>. Eso es trivial en este caso simple.<\/li>\n\n\n\n<li>La soluci\u00f3n m\u00e1s elegante es el mecanismo de \u00abnotificaci\u00f3n\u00bb de la clase <em><code>TComponent<\/code><\/em>. Se puede notificar a un componente cuando se libera otro componente y, por lo tanto, establecer su referencia en <em><code>nil<\/code><\/em>.<\/li>\n\n\n\n<li>Por lo tanto, obtienes algo as\u00ed como una referencia d\u00e9bil. Puede hacer frente a varios escenarios de uso, por ejemplo, puede dejar que el c\u00f3digo externo a la clase establezca su referencia, y el c\u00f3digo externo tambi\u00e9n puede liberar la instancia en cualquier momento.<\/li>\n\n\n\n<li>Esto requiere que ambas clases desciendan de <em><code>TComponent<\/code><\/em>. Usarlo en general se reduce a llamar a <em><code>FreeNotification<\/code><\/em> , <em><code>RemoveFreeNotification<\/code><\/em> y anular Notificaci\u00f3n.<\/li>\n\n\n\n<li>Esto requiere que ambas clases desciendan de <em><code>TComponent<\/code><\/em>. Usarlo en general se reduce a llamar a <em><code>FreeNotification<\/code><\/em> , <em><code>RemoveFreeNotification<\/code><\/em> y anular Notificaci\u00f3n.<\/li>\n<\/ul>\n\n\n\n<p>Aqu\u00ed hay un ejemplo completo que muestra c\u00f3mo usar este mecanismo, junto con el constructor\/destructor y una propiedad <em><code>setter<\/code><\/em>. A veces se puede hacer m\u00e1s simple, pero esta es la versi\u00f3n completa que siempre es correcta \ud83d\ude42<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">type\n  TControl = class(TComponent)\n  end;\n\n  TContainer = class(TComponent)\n  private\n    FSomeSpecialControl: TControl;\n    procedure SetSomeSpecialControl(const Value: TControl);\n  protected\n    procedure Notification(AComponent: TComponent; Operation: TOperation); override;\n  public\n    destructor Destroy; override;\n    property SomeSpecialControl: TControl\n      read FSomeSpecialControl write SetSomeSpecialControl;\n  end;\n\nimplementation\n\nprocedure TContainer.Notification(AComponent: TComponent; Operation: TOperation);\nbegin\n  inherited;\n  if (Operation = opRemove) and (AComponent = FSomeSpecialControl) then\n    { Se iguala a Nil por SetSomeSpecialControl para hacer una correcta liberaci\u00f3n }\n    SomeSpecialControl := nil;\nend;\n\nprocedure TContainer.SetSomeSpecialControl(const Value: TControl);\nbegin\n  if FSomeSpecialControl &lt;&gt; Value then\n  begin\n    if FSomeSpecialControl &lt;&gt; nil then\n      FSomeSpecialControl.RemoveFreeNotification(Self);\n    FSomeSpecialControl := Value;\n    if FSomeSpecialControl &lt;&gt; nil then\n      FSomeSpecialControl.FreeNotification(Self);\n  end;\nend;\n\ndestructor TContainer.Destroy;\nbegin\n  {  Se iguala a Nil por SetSomeSpecialControl, para desactivar la notificaci\u00f3n de liberaci\u00f3n }\n  SomeSpecialControl := nil;\n  inherited;\nend;<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Observador de notificaciones  (Castle Game Engine)<\/h3>\n\n\n\n<p>En Castle Game Engine recomendamos usar <em><code>TFreeNotificationObserver<\/code><\/em> de la unidad <em><code>CastleClassUtils<\/code><\/em> en lugar de llamar directamente a <em><code>FreeNotification<\/code><\/em>, <em><code>RemoveFreeNotification<\/code><\/em> y anular Notificaci\u00f3n.<\/p>\n\n\n\n<p>En general, usar <em><code>TFreeNotificationObserver<\/code><\/em> parece un poco m\u00e1s simple que usar el mecanismo <em><code>FreeNotification<\/code><\/em> directamente (aunque admito que es cuesti\u00f3n de gustos). Pero, en particular, cuando se debe observar la misma instancia de clase por m\u00faltiples razones, <em>TFreeNotificationObserver<\/em> es mucho m\u00e1s f\u00e1cil de usar (el uso directo de <em>FreeNotification<\/em> en este caso puede complicarse, ya que debe estar atento para no cancelar el registro de la notificaci\u00f3n demasiado pronto).<\/p>\n\n\n\n<p>Este es el c\u00f3digo de ejemplo que usa <em><code>TFreeNotificationObserver<\/code><\/em>, para lograr el mismo efecto que el ejemplo en la secci\u00f3n anterior:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">type\n  TControl = class(TComponent)\n  end;\n\n  TContainer = class(TComponent)\n  private\n    FSomeSpecialControlObserver: TFreeNotificationObserver;\n    FSomeSpecialControl: TControl;\n    procedure SetSomeSpecialControl(const Value: TControl);\n    procedure SomeSpecialControlFreeNotification(const Sender: TFreeNotificationObserver);\n  public\n    constructor Create(AOwner: TComponent); override;\n    property SomeSpecialControl: TControl\n      read FSomeSpecialControl write SetSomeSpecialControl;\n  end;\n\nimplementation\n\nuses CastleComponentSerialize;\n\nconstructor TContainer.Create(AOwner: TComponent);\nbegin\n  inherited;\n  FSomeSpecialControlObserver := TFreeNotificationObserver.Create(Self);\n  FSomeSpecialControlObserver.OnFreeNotification := {$ifdef FPC}@{$endif} SomeSpecialControlFreeNotification;\nend;\n\nprocedure TContainer.SetSomeSpecialControl(const Value: TControl);\nbegin\n  if FSomeSpecialControl &lt;&gt; Value then\n  begin\n    FSomeSpecialControl := Value;\n    FSomeSpecialControlObserver.Observed := Value;\n  end;\nend;\n\nprocedure TContainer.SomeSpecialControlFreeNotification(const Sender: TFreeNotificationObserver);\nbegin\n\n\/\/ Igualar la propiedad a Nil, cuando el componente de referencia es liberado\n  SomeSpecialControl := nil;\nend;<\/pre><\/div>\n\n\n\n<p>Ver <a href=\"https:\/\/castle-engine.io\/custom_components\">https:\/\/castle-engine.io\/custom_components<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Excepciones<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Descripci\u00f3n general<\/h3>\n\n\n\n<p>Las excepciones permiten interrumpir la ejecuci\u00f3n normal del c\u00f3digo.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>En cualquier punto dentro del programa, puede generar una excepci\u00f3n utilizando la palabra clave <em>raise<\/em>.En efecto, las l\u00edneas de c\u00f3digo que siguen a la llamada <em>raise<\/em>\u2026 no se ejecutar\u00e1n<\/li>\n\n\n\n<li>Se puede capturar una excepci\u00f3n usando una construcci\u00f3n try\u2026except\u2026end. Detectar una excepci\u00f3n significa que de alguna manera \u00ablidias\u00bb con la excepci\u00f3n, y el siguiente c\u00f3digo deber\u00eda ejecutarse como de costumbre, la excepci\u00f3n ya no se propaga hacia arriba.\n<ul class=\"wp-block-list\">\n<li>Nota: Si se genera una excepci\u00f3n pero nunca se detecta, har\u00e1 que toda la aplicaci\u00f3n se detenga con un error. Pero en las aplicaciones LCL, las excepciones siempre se detectan alrededor de los eventos (y provocan el cuadro de di\u00e1logo LCL) si no las detecta antes.<\/li>\n\n\n\n<li>En las aplicaciones de Castle Game Engine que usan CastleWindow, de manera similar, siempre detectamos excepciones en torno a sus eventos (y mostramos el cuadro de di\u00e1logo adecuado).<\/li>\n\n\n\n<li>Por lo tanto, no es tan f\u00e1cil hacer una excepci\u00f3n que no se detecte en ninguna parte (no se detecte en su c\u00f3digo, c\u00f3digo LCL, c\u00f3digo CGE\u2026).<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Si bien una excepci\u00f3n interrumpe la ejecuci\u00f3n, puede usar la construcci\u00f3n try\u2026finally\u2026end para ejecutar alg\u00fan c\u00f3digo siempre, incluso si el c\u00f3digo fue interrumpido por una excepci\u00f3n. <\/li>\n\n\n\n<li>La construcci\u00f3n try\u2026finally\u2026end tambi\u00e9n funciona cuando el c\u00f3digo es interrumpido por las palabras clave Break, Continue o Exit. El objetivo es ejecutar siempre el c\u00f3digo en la secci\u00f3n finalmente.<\/li>\n<\/ul>\n\n\n\n<p>Una \u00abexcepci\u00f3n\u00bb es, en general, es una instancia de una clase.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>El compilador no impone ninguna clase en particular. Solo debe llamar a raise XXX donde XXX es una instancia de cualquier clase. Cualquier clase (por lo tanto, cualquier cosa que descienda de TObject) ser\u00e1 correcto.<\/li>\n\n\n\n<li>Es una convenci\u00f3n est\u00e1ndar que las clases de excepci\u00f3n desciendan de una clase de excepci\u00f3n especial. La clase Exception extiende TObject, agregando una propiedad Message de cadena y un constructor para configurar f\u00e1cilmente esta propiedad. Todas las excepciones generadas por la biblioteca est\u00e1ndar descienden de Exception. Recomendamos seguir esta convenci\u00f3n. <\/li>\n\n\n\n<li>Las clases de excepci\u00f3n (por convenci\u00f3n) tienen nombres que comienzan con E, no con T. Como ESomethingBadHappened.<\/li>\n\n\n\n<li>El compilador liberar\u00e1 autom\u00e1ticamente el objeto de excepci\u00f3n cuando se maneje. No lo liberes t\u00fa mismo. <\/li>\n\n\n\n<li>En la mayor\u00eda de los casos, simplemente construyes el objeto al mismo tiempo que llamas a <em>raise<\/em>, como <em>raise EAlgoMalOcurrido.Crear(&#8216;Descripci\u00f3n de lo malo que suce<\/em>di\u00f3&#8217;).<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Levantamiento, elevaci\u00f3n, propagaci\u00f3n (Raising)<\/h3>\n\n\n\n<p>Si desea generar su propia excepci\u00f3n, declararla y llame a la elevaci\u00f3n (<em>raise)<\/em>\u2026 cuando corresponda:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">type\n  EInvalidParameter = class(Exception);\n\nfunction ReadParameter: String;\nbegin\n  Result := Readln;\n  if Pos(' ', Result) &lt;&gt; 0 then\n    raise EInvalidParameter.Create('Invalid parameter, space is not allowed');\nend;<\/pre><\/div>\n\n\n\n<p>Tenga en cuenta que la expresi\u00f3n que sigue a la elevaci\u00f3n debe ser una instancia de clase v\u00e1lida para elevar. Casi siempre crear\u00e1 la instancia de excepci\u00f3n aqu\u00ed. <\/p>\n\n\n\n<p>Tambi\u00e9n puede usar el constructor <em>CreateFmt<\/em>, que es un atajo c\u00f3modo para <em><code>Create(Format(MessageFormat, MessageArguments))<\/code>.<\/em> Esta es una forma com\u00fan de proporcionar m\u00e1s informaci\u00f3n al mensaje de excepci\u00f3n. Podemos mejorar el ejemplo anterior as\u00ed:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">type\n  EInvalidParameter = class(Exception);\n\nfunction ReadParameter: String;\nbegin\n  Result := Readln;\n  if Pos(' ', Result) &lt;&gt; 0 then\n    raise EInvalidParameter.CreateFmt('Par\u00e1metro invalido %s, espacio no est\u00e1 permitido', [Result]);\nend;<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Atrapando<\/h3>\n\n\n\n<p>Puede detectar una excepci\u00f3n como esta:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">var\n  Parameter1, Parameter2, Parameter3: String;\nbegin\n  try\n    Writeln('Input 1st parameter:');\n    Parameter1 := ReadParameter;\n    Writeln('Input 2nd parameter:');\n    Parameter2 := ReadParameter;\n    Writeln('Input 3rd parameter:');\n    Parameter3 := ReadParameter;\n  except\n    \/\/Captura EInvalidParameter elevada por alguno de las l\u00edneas que llaman a ReadParametes  \n   on EInvalidParameter do\n      Writeln('Ocurri\u00f3 la excepci\u00f3n EInvalidParameter');\n  end;\nend;<\/pre><\/div>\n\n\n\n<p>Para mejorar el ejemplo anterior, podemos declarar el nombre de la instancia de excepci\u00f3n (usaremos E en el ejemplo). De esta manera podemos imprimir el mensaje de excepci\u00f3n:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">try\n...\nexcept\n  on E: EInvalidParameter do\n    Writeln('Ocurri\u00f3 la excepci\u00f3n EInvalidParameter con el mensaje: ' + E.Message);\nend;<\/pre><\/div>\n\n\n\n<p>O tambi\u00e9n podemos comprobar clases de excepciones<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">try\n...\nexcept\n  on E: EInvalidParameter do\n    Writeln('Ocurri\u00f3 la excepci\u00f3n EInvalidParameter con el mensaje: ' + E.Message);\n  on E: ESomeOtherException do\n    Writeln('Ocurri\u00f3 la excepci\u00f3n ESomeOtherException con el mensaje:: ' + E.Message);\nend;<\/pre><\/div>\n\n\n\n<p>Tambi\u00e9n puede reaccionar a cualquier excepci\u00f3n generada, si no usa ninguna expresi\u00f3n:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">try\n...\nexcept\n  Writeln('Atenci\u00f3n: ocurri\u00f3 alguna excepci\u00f3n');\nend;\n\/\/ATENCI\u00d3N: NO SIGAS ESTE EJEMPLO SIN LEER EL AVISO M\u00c1S ABAJO\n\/\/SOBRE COMO CAPTURAR TODAS LAS EXCEPCIONES\n<\/pre><\/div>\n\n\n\n<p>En general, solo debe capturar excepciones de una clase espec\u00edfica, que se\u00f1alan un problema particular con el que sabe qu\u00e9 hacer. Tenga cuidado con la captura de excepciones de tipo general (como la captura de cualquier excepci\u00f3n o cualquier TObject), ya que puede capturar f\u00e1cilmente demasiadas y luego causar problemas al depurar otros problemas. <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\u00bfLa excepci\u00f3n indica un problema en la entrada del usuario?<\/li>\n\n\n\n<li> Entonces deber\u00edas reportarlo al usuario.<\/li>\n\n\n\n<li>\u00bfLa excepci\u00f3n indica un error en su c\u00f3digo? Luego, debe corregir el c\u00f3digo para evitar que ocurra la excepci\u00f3n.<\/li>\n<\/ul>\n\n\n\n<p>Otra forma de capturar todas las excepciones es usar:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">try\n...\nexcept\n  Writeln('Atenci\u00f3n: ocurri\u00f3 alguna excepci\u00f3n');\nend;\n\/\/ATENCI\u00d3N: NO SIGAS ESTE EJEMPLO SIN LEER EL AVISO M\u00c1S ABAJO\n\/\/SOBRE COMO CAPTURAR TODAS LAS EXCEPCIONES\n<\/pre><\/div>\n\n\n\n<p>Aunque normalmente es suficiente para capturar <code><em>Exception<\/em><\/code>:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">try\n...\nexcept\n  on E: Exception do\n    Writeln('Atenci\u00f3n, ocurri\u00f3 una excepci\u00f3n: ' + E.ClassName + ', message: ' + E.Message);\nend;\n\/\/ATENCI\u00d3N: NO SIGAS ESTE EJEMPLO SIN LEER EL AVISO M\u00c1S ABAJO\n\/\/SOBRE COMO CAPTURAR TODAS LAS EXCEPCIONES<\/pre><\/div>\n\n\n\n<p>Puede \u00abvolver a generar\u00bb la excepci\u00f3n en el bloque <em><code>except\u2026 finally<\/code><\/em>, si as\u00ed lo decide. Puede hacer aumentar E si la instancia de excepci\u00f3n es E, tambi\u00e9n puede usar aumentar sin par\u00e1metros. Por ejemplo:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">try\n...\nexcept\n  on E: EInvalidSoundFile do\n  begin\n    if E.InvalidUrl = 'http:\/\/example.com\/blablah.wav' then\n      Writeln('ATenci\u00f3n:  http:\/\/example.com\/blablah.wav fall\u00f3 la carga, ignorelo')\n    else\n      raise;\n  end;\nend;<\/pre><\/div>\n\n\n\n<p>Tenga en cuenta que, aunque la excepci\u00f3n es una instancia de un objeto, nunca debe liberarlo manualmente despu\u00e9s de generarlo. El compilador generar\u00e1 el c\u00f3digo adecuado que se asegura de liberar el objeto de excepci\u00f3n una vez que se maneja.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Finalmente (hacer cosas sin importar si ocurri\u00f3 una excepci\u00f3n)<\/h3>\n\n\n\n<p>A menudo usas <em><code>try<\/code><\/em> .. La forma de escribirlo se ve as\u00ed:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">procedure MyProcedure;\nvar\n  MyInstance: TMyClass;\nbegin\n  MyInstance := TMyClass.Create;\n  try\n    MyInstance.DoSomething;\n    MyInstance.DoSomethingElse;\n  finally\n    FreeAndNil(MyInstance);\n  end;\nend;<\/pre><\/div>\n\n\n\n<p>Esto siempre funciona de manera confiable y no provoca p\u00e9rdidas de memoria, incluso si <em><code>MyInstance.DoSomething <\/code><\/em>o <code><em>MyInstance.DoSomethingElse<\/em><\/code> generan una excepci\u00f3n.<\/p>\n\n\n\n<p>Tenga en cuenta que esto tiene en cuenta que las variables locales, como <em><code>MyInstance<\/code><\/em> arriba, tienen valores indefinidos (pueden contener \u00abbasura de memoria\u00bb aleatoria) antes de la primera asignaci\u00f3n. Es decir, escribir algo como esto no ser\u00eda v\u00e1lido:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">\/\/ Ejemplo incorrecto\nprocedure MyProcedure;\nvar\n  MyInstance: TMyClass;\nbegin\n  try\n    CallSomeOtherProcedure;\n    MyInstance := TMyClass.Create;\n    MyInstance.DoSomething;\n    MyInstance.DoSomethingElse;\n  finally\n    FreeAndNil(MyInstance);\n  end;\nend;<\/pre><\/div>\n\n\n\n<p>El ejemplo anterior no es v\u00e1lido: si ocurre una excepci\u00f3n dentro de <em><code>TMyClass.Create <\/code><\/em>(un constructor tambi\u00e9n puede generar una excepci\u00f3n), o dentro de CallSomeOtherProcedure, entonces la variable <em><code>MyInstance<\/code><\/em> no se inicializa. Llamar a <code><em>FreeAndNil(MyInstance)<\/em><\/code> intentar\u00e1 llamar al destructor de <em><code>MyInstance<\/code><\/em>, que probablemente se bloquee con una infracci\u00f3n de acceso (falla de segmentaci\u00f3n). En efecto, una excepci\u00f3n provoca otra excepci\u00f3n, lo que har\u00e1 que el informe de errores no sea muy \u00fatil: no ver\u00e1 el mensaje de la excepci\u00f3n original.<\/p>\n\n\n\n<p>A veces se justifica arreglar el c\u00f3digo anterior inicializando primero todas las variables locales a cero (en las que llamar a <em><code>FreeAndNil<\/code><\/em> es seguro y no har\u00e1 nada). Esto tiene sentido si libera muchas instancias de clase. As\u00ed que los dos ejemplos de c\u00f3digo a continuaci\u00f3n funcionan igual de bien:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">procedure MyProcedure;\nvar\n  MyInstance1: TMyClass1;\n  MyInstance2: TMyClass2;\n  MyInstance3: TMyClass3;\nbegin\n  MyInstance1 := TMyClass1.Create;\n  try\n    MyInstance1.DoSomething;\n\n    MyInstance2 := TMyClass2.Create;\n    try\n      MyInstance2.DoSomethingElse;\n\n      MyInstance3 := TMyClass3.Create;\n      try\n        MyInstance3.DoYetAnotherThing;\n      finally\n        FreeAndNil(MyInstance3);\n      end;\n    finally\n      FreeAndNil(MyInstance2);\n    end;\n  finally\n    FreeAndNil(MyInstance1);\n  end;\nend;<\/pre><\/div>\n\n\n\n<p>Probablemente sea m\u00e1s legible de la siguiente forma:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">procedure MyProcedure;\nvar\n  MyInstance1: TMyClass1;\n  MyInstance2: TMyClass2;\n  MyInstance3: TMyClass3;\nbegin\n  MyInstance1 := nil;\n  MyInstance2 := nil;\n  MyInstance3 := nil;\n  try\n    MyInstance1 := TMyClass1.Create;\n    MyInstance1.DoSomething;\n\n    MyInstance2 := TMyClass2.Create;\n    MyInstance2.DoSomethingElse;\n\n    MyInstance3 := TMyClass3.Create;\n    MyInstance3.DoYetAnotherThing;\n  finally\n    FreeAndNil(MyInstance3);\n    FreeAndNil(MyInstance2);\n    FreeAndNil(MyInstance1);\n  end;\nend;<\/pre><\/div>\n\n\n\n<p>Nota:<br>En este ejemplo simple, tambi\u00e9n podr\u00eda presentar un argumento v\u00e1lido de que el c\u00f3digo debe dividirse en 3 procedimientos separados, uno llam\u00e1ndose entre s\u00ed.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">C\u00f3mo se muestran las excepciones en varias bibliotecas<\/h3>\n\n\n\n<p>En el caso de Lazarus LCL, las excepciones generadas durante los eventos (varias devoluciones de llamada asignadas a las propiedades OnXxx de los componentes LCL) se capturar\u00e1n y dar\u00e1n como resultado un agradable mensaje de di\u00e1logo que permite al usuario continuar y detener la aplicaci\u00f3n. Esto significa que sus propias excepciones no \u00absalen\u00bb de <em><code>Application.ProcessMessages<\/code><\/em>, por lo que no rompen autom\u00e1ticamente la aplicaci\u00f3n. Puede configurar lo que sucede usando <em><code>TApplicationProperties.OnException<\/code><\/em>. De manera similar, en el caso de Castle Game Engine con <em>CastleWindow<\/em>: la excepci\u00f3n se captura internamente y da como resultado un buen mensaje de error. Por lo tanto, las excepciones no \u00absalen\u00bb de <code><em>Application.ProcessMessages<\/em><\/code>. Nuevamente, puede configurar lo que sucede usando <code><em>Application.OnException<\/em><\/code>.<\/p>\n\n\n\n<p>Algunas otras bibliotecas GUI pueden hacer algo similar a lo anterior.<\/p>\n\n\n\n<p>En el caso de otras aplicaciones, puede configurar c\u00f3mo se muestra la excepci\u00f3n asignando una devoluci\u00f3n de llamada global a <code><em>OnHaltProgram<\/em><\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Biblioteca en tiempo de ejecuci\u00f3n (Run-time)<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Input\/output using streams<\/h3>\n\n\n\n<p>Los programas modernos deber\u00edan usar la clase <em><code>TStream<\/code><\/em> y sus muchos descendientes para hacer entrada\/salida. Tiene muchos descendientes \u00fatiles, como <em><code>TFileStream<\/code><\/em>, <em><code>TMemoryStream<\/code><\/em>, <em><code>TStringStream<\/code><\/em>.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses\n  SysUtils, Classes;\n\nvar\n  S: TStream;\n  InputInt, OutputInt: Integer;\nbegin\n  InputInt := 666;\n\n  S := TFileStream.Create('my_binary_file.data', fmCreate);\n  try\n    S.WriteBuffer(InputInt, SizeOf(InputInt));\n  finally\n    FreeAndNil(S);\n  end;\n\n  S := TFileStream.Create('my_binary_file.data', fmOpenRead);\n  try\n    S.ReadBuffer(OutputInt, SizeOf(OutputInt));\n  finally\n    FreeAndNil(S);\n  end;\n\n  WriteLn('Se obtuvo un entero de la lectura del fichero: ', OutputInt);\nend.<\/pre><\/div>\n\n\n\n<p>En<strong> Castle Game Engine<\/strong>: debe usar la funci\u00f3n de descarga para crear una transmisi\u00f3n que obtenga datos de cualquier URL. Los archivos regulares, los recursos HTTP y HTTPS, los activos de Android y  son compatibles de esta manera. Adem\u00e1s, para acceder el recurso dentro de los datos de tu juego (en el subdirectorio de datos) usa la URL especial castle-data:\/xxx. Ejemplos:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">EnableNetwork := true;\nS := Download('https:\/\/castle-engine.io\/latest.zip');<\/pre><\/div>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">S := Download('file:\/\/\/home\/michalis\/my_binary_file.data');<\/pre><\/div>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">S := Download('castle-data:\/gui\/my_image.png');<\/pre><\/div>\n\n\n\n<p>Para leer archivos de texto, recomendamos utilizar la clase <em>TTextReader<\/em>. Proporciona una API orientada a la l\u00ednea y envuelve un TStream en su interior. El constructor TTextReader puede tomar una URL, o puede pasar all\u00ed su fuente TStream personalizada.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">Text := TTextReader.Create('castle-data:\/my_data.txt');\ntry\n  while not Text.Eof do\n    WriteLnLog('NextLine', Text.ReadLn);\nfinally\n  FreeAndNil(Text);\nend;<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Contenedores (Listas, diccionarios) usando gen\u00e9ricos<\/h3>\n\n\n\n<p>La biblioteca de idiomas y tiempo de ejecuci\u00f3n ofrece varios contenedores flexibles. Hay una serie de clases no gen\u00e9ricas (como <em><code>TList<\/code><\/em> y <em><code>TObjectList<\/code><\/em> de la unidad <em><code>Contnrs<\/code><\/em>), tambi\u00e9n hay matrices din\u00e1micas (matriz de <em><code>TMyType<\/code><\/em>). Pero para obtener la mayor flexibilidad y seguridad de tipos, recomiendo usar contenedores gen\u00e9ricos para la mayor\u00eda de sus necesidades.<\/p>\n\n\n\n<p>Los contenedores gen\u00e9ricos le brindan muchos m\u00e9todos \u00fatiles para agregar, eliminar, iterar, buscar, clasificar\u2026 El compilador tambi\u00e9n sabe (y verifica) que el contenedor contiene solo elementos del tipo apropiado.<\/p>\n\n\n\n<p>Hay tres bibliotecas que proporcionan contenedores gen\u00e9ricos en FPC:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Unidad Generics.Collections y amigos (desde FPC &gt;= 3.2.0)<\/li>\n\n\n\n<li>Unidad FGL<\/li>\n\n\n\n<li>Unidad GVector y amigos (juntos en fcl-stl)<\/li>\n<\/ul>\n\n\n\n<p>Recomendamos utilizar la unidad Generics.Collections. Los contenedores gen\u00e9ricos que implementan:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Paquete completo de caracter\u00edscticas \u00fatiles<\/li>\n\n\n\n<li>Muy eficiente, en particular para acceder a diccionarios por su clave<\/li>\n\n\n\n<li>Compatible con FPC y Delphi.<\/li>\n\n\n\n<li>Nombre coherente con la biblioteca est\u00e1ndar.<\/li>\n<\/ul>\n\n\n\n<p>En Castle Game Engine: utilizamos Generics.Collections de forma intensiva en todo el motor y le recomendamos que utilice Generics.Collections tambi\u00e9n en sus aplicaciones.<\/p>\n\n\n\n<p>Las clases m\u00e1s importantes de la unidad Generics.Collections son:<\/p>\n\n\n\n<p><strong>Lista TL<\/strong>: Una lista gen\u00e9rica de tipos.<\/p>\n\n\n\n<p><strong>TObjectList<\/strong>: Una lista gen\u00e9rica de instancias de objetos. Puede \u00abposeer\u00bb hijos, lo que significa que los liberar\u00e1 autom\u00e1ticamente.<\/p>\n\n\n\n<p><strong>TDiccionario<\/strong>:  Un diccionario gen\u00e9rico.<\/p>\n\n\n\n<p><strong>TObjectDiccionario<\/strong>: Un diccionario gen\u00e9rico, que puede \u00abposeer\u00bb las claves y\/o valores.<\/p>\n\n\n\n<p>Aqu\u00ed le mostramos c\u00f3mo usar una TObjectList gen\u00e9rica simple:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses SysUtils, Generics.Collections;\n\ntype\n  TApple = class\n    Name: string;\n  end;\n\n  TAppleList = specialize TObjectList&lt;TApple&gt;;\n\nvar\n  A: TApple;\n  Apples: TAppleList;\nbegin\n  Apples := TAppleList.Create(true);\n  try\n    A := TApple.Create;\n    A.Name := 'mi manzana';\n    Apples.Add(A);\n\n    A := TApple.Create;\n    A.Name := 'otra manzana';\n    Apples.Add(A);\n\n    Writeln('Count: ', Apples.Count);\n    Writeln(Apples[0].Name);\n    Writeln(Apples[1].Name);\n  finally \n   FreeAndNil(Apples);\n end;\nend.<\/pre><\/div>\n\n\n\n<p>Tenga en cuenta que algunas operaciones requieren comparar dos elementos, como ordenar y buscar (por ejemplo, mediante los m\u00e9todos <em><code>Sort<\/code><\/em> e <em><code>IndexOf<\/code><\/em>). Los contenedores Generics.Collections utilizan para esto un comparador. El comparador predeterminado es razonable para todos los tipos, incluso para registros (en cuyo caso compara el contenido de la memoria, que es un valor predeterminado razonable al menos para buscar usando <em>IndexOf<\/em>).<\/p>\n\n\n\n<p>Al ordenar la lista, puede proporcionar un comparador personalizado como par\u00e1metro. El comparador es una clase que implementa la interfaz <em>IComparer<\/em>. En la pr\u00e1ctica, normalmente define la devoluci\u00f3n de llamada adecuada y usa el m\u00e9todo <em>TComparer.Construct<\/em> para envolver esta devoluci\u00f3n de llamada en una instancia de <em>IComparer<\/em>. A continuaci\u00f3n se muestra un ejemplo de c\u00f3mo hacerlo:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses SysUtils, Generics.Defaults, Generics.Collections;\n\ntype\n  TApple = class\n    Name: string;\n  end;\n\n  TAppleList = specialize TObjectList&lt;TApple&gt;;\n\nfunction CompareApples(constref Left, Right: TApple): Integer;\nbegin\n  Result := AnsiCompareStr(Left.Name, Right.Name);\nend;\n\ntype\n  TAppleComparer = specialize TComparer&lt;TApple&gt;;\nvar\n  A: TApple;\n  L: TAppleList;\nbegin\n  L := TAppleList.Create(true);\n  try\n    A := TApple.Create;\n    A.Name := '11';\n    L.Add(A);\n\n    A := TApple.Create;\n    A.Name := '33';\n    L.Add(A);\n\n    A := TApple.Create;\n    A.Name := '22';\n    L.Add(A);\n\n    L.Sort(TAppleComparer.Construct(@CompareApples));\n\n    Writeln('Count: ', L.Count);\n    Writeln(L[0].Name);\n    Writeln(L[1].Name);\n    Writeln(L[2].Name);\n  finally FreeAndNil(L) end;\nend.<\/pre><\/div>\n\n\n\n<p>La clase <em><code>TDictionary<\/code><\/em> implementa un diccionario, tambi\u00e9n conocido como mapa (clave \u2192 valor), tambi\u00e9n conocido como matriz asociativa. Su API es un poco similar a la clase C# TDictionary. Tiene iteradores \u00fatiles para claves, valores y pares de clave\u2192valor.<\/p>\n\n\n\n<p>Un c\u00f3digo de ejemplo usando un diccionario:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses SysUtils, Generics.Collections;\n\ntype\n  TApple = class\n    Name: string;\n  end;\n\n  TAppleDictionary = specialize TDictionary&lt;string, TApple&gt;;\n\nvar\n  Apples: TAppleDictionary;\n  A, FoundA: TApple;\n  ApplePair: TAppleDictionary.TDictionaryPair;\n  AppleKey: string;\nbegin\n  Apples := TAppleDictionary.Create;\n  try\n    A := TApple.Create;\n    A.Name := 'mi manzana';\n    Apples.AddOrSetValue('manzana clave 1', A);\n\n    if Apples.TryGetValue('manzana clave 1', FoundA) then\n      Writeln('Encontrada manzana bajo la clave : \"manzana clave 1\", con el nombre: ' +\n        FoundA.Name);\n\n    for AppleKey in Apples.Keys do\n      Writeln('Encontrada clave manzana: ' + AppleKey);\n    for A in Apples.Values do\n      Writeln('Encontrada clave manzana: ' + A.Name);\n    for ApplePair in Apples do\n      Writeln('Encontrada manza Clave-&gt;Valor: ' +\n        ApplePair.Key + '-&gt;' + ApplePair.Value.Name);\n\n    { La l\u00ednea inferior tambien funciona, pero solo puede\n    ser usada para modificar una clave existente en el diccionario }\n    \/\/ Apples['manzana clave 1'] := ... ;\n\n    Apples.Remove('manzana clave 1');\n\n    { Observa que TDictionary no es propietario de sus elementos\n    por tanto debes liberarlos por ti mismo.\n    Podemos usar TObjectDictionary para usar el m\u00e9todo automatico}\n    A.Free;\n    finally \n    FreeAndNil(Apples) \nend;\nend.<\/pre><\/div>\n\n\n\n<p><em><code>TObjectDictionary<\/code><\/em> tambi\u00e9n puede poseer las claves y\/o valores del diccionario, lo que significa que se liberar\u00e1n autom\u00e1ticamente. Tenga cuidado de poseer solo claves y\/o valores si son instancias de objetos. Si configura \u00abproperty\u00bb de alg\u00fan otro tipo, como un n\u00famero entero (por ejemplo, si sus claves son n\u00fameros enteros e incluye <em>doOwnsKeys<\/em>), obtendr\u00e1 un bloqueo desagradable cuando se ejecute el c\u00f3digo.<\/p>\n\n\n\n<p>A continuaci\u00f3n se muestra un c\u00f3digo de ejemplo que usa <em><code>TObjectDictionary<\/code><\/em>. Compile este ejemplo con la detecci\u00f3n de fugas de memoria, como fpc -gl -gh <em><code>generics_object_dictionary.lpr<\/code><\/em>, para ver que todo se libera cuando se cierra el programa.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses SysUtils, Generics.Collections;\n\ntype\n  TApple = class\n    Name: string;\n  end;\n\n  TAppleDictionary = specialize TObjectDictionary&lt;string, TApple&gt;;\n\nvar\n  Apples: TAppleDictionary;\n  A: TApple;\n  ApplePair: TAppleDictionary.TDictionaryPair;\nbegin\n  Apples := TAppleDictionary.Create([doOwnsValues]);\n  try\n    A := TApple.Create;\n    A.Name := 'my apple';\n    Apples.AddOrSetValue('manzana clave 1', A);\n\n    for ApplePair in Apples do\n      Writeln('Encontrda manzana clave-&gt;valor: ' +\n        ApplePair.Key + '-&gt;' + ApplePair.Value.Name);\n\n    Apples.Remove('manzana clave 1');\n  finally \n    FreeAndNil(Apples) \nend;\nend.<\/pre><\/div>\n\n\n\n<p>Si prefiere usar la unidad FGL en lugar de Generics.Collections, las clases m\u00e1s importantes de la unidad FGL son:<\/p>\n\n\n\n<p><strong>Lista TFPGL<\/strong>: Una lista gen\u00e9rica de tipos.<\/p>\n\n\n\n<p><strong>TFPGObjectList<\/strong>:  Una lista gen\u00e9rica de instancias de objetos. Puede \u00abposeer\u00bb hijos.<\/p>\n\n\n\n<p><strong>TFPGMapa<\/strong>:  Un diccionario gen\u00e9rico.<\/p>\n\n\n\n<p>En la unidad FGL, <em><code>TFPGList<\/code><\/em> solo se puede usar para tipos para los que se define el operador de igualdad (=). Para <em><code>TFPGMap<\/code><\/em>, los operadores \u00abmayor que\u00bb (&gt;) y \u00abmenor que\u00bb (&lt;) deben definirse para el tipo de clave. Si desea utilizar estas listas con tipos que no tienen operadores de comparaci\u00f3n incorporados (por ejemplo, con registros), debe sobrecargar sus operadores como se muestra en la sobrecarga de operadores.<\/p>\n\n\n\n<p>En Castle Game Engine incluimos una unidad <em><code>CastleGenericLists<\/code><\/em> que agrega las clases <em><code>TGenericStructList<\/code><\/em> y <em><code>TGenericStructMap<\/code><\/em>. Son similares a <em><code>TFPGList<\/code><\/em> y <em><code>TFPGMap<\/code><\/em>, pero no requieren una definici\u00f3n de los operadores de comparaci\u00f3n para el tipo apropiado (en su lugar, comparan los contenidos de la memoria, lo que suele ser apropiado para registros o punteros de m\u00e9todos). Pero la unidad <em><code>CastleGenericLists<\/code><\/em> est\u00e1 obsoleta desde la versi\u00f3n 6.3 del motor, ya que recomendamos usar <code><em>Generics.Collections<\/em><\/code> en su lugar.<\/p>\n\n\n\n<p>Si desea obtener m\u00e1s informaci\u00f3n sobre los gen\u00e9ricos, consulte Gen\u00e9ricos.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Clonaci\u00f3n: TPersistent.Assign <\/h3>\n\n\n\n<p>Al copiar las instancias de clase mediante un operador de asignaci\u00f3n simple, se copia la referencia.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">var\n  X, Y: TMyObject;\nbegin\n  X := TMyObject.Create;\n  Y := X;\n  \/\/ X y Y ahora son dos punteros a los mismos datos\n   Y.MyField := 123; \/\/ this also changes X.MyField\n  FreeAndNil(X);\nend;<\/pre><\/div>\n\n\n\n<p>Para copiar el contenido de la instancia de clase, el enfoque est\u00e1ndar es derivar su clase de <em><code>TPersistent<\/code><\/em> y anular su m\u00e9todo <em><code>Assign<\/code><\/em>. Una vez que se implementa correctamente en <em><code>TMyObject<\/code><\/em>, lo usa as\u00ed:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">var\n  X, Y: TMyObject;\nbegin\n  X := TMyObject.Create;\n  Y := TMyObject.Create;\n  Y.Assign(X);\n  Y.MyField := 123; \/\/ Esto no cambia  X.MyField\n  FreeAndNil(X);\n  FreeAndNil(Y);\nend;<\/pre><\/div>\n\n\n\n<p>Para que funcione, debe implementar el m\u00e9todo <code>Assign<\/code> para copiar realmente los campos que desea. Debe implementar cuidadosamente el m\u00e9todo <em><code>Assign<\/code><\/em>, para copiar de una clase que puede ser descendiente de la clase actual.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses\n  SysUtils, Classes;\n\ntype\n  TMyClass = class(TPersistent)\n  public\n    MyInt: Integer;\n    procedure Assign(Source: TPersistent); override;\n  end;\n\n  TMyClassDescendant = class(TMyClass)\n  public\n    MyString: string;\n    procedure Assign(Source: TPersistent); override;\n  end;\n\nprocedure TMyClass.Assign(Source: TPersistent);\nvar\n  SourceMyClass: TMyClass;\nbegin\n  if Source is TMyClass then\n  begin\n    SourceMyClass := TMyClass(Source);\n    MyInt := SourceMyClass.MyInt;\n    \/\/ Xxx := SourceMyClass.Xxx; \/\/ A\u00f1adir nuevos campos aqu\u00ed\n  end else\n    { Ya que  TMyClass es un descendiente directo de TPersistent,\n      este llama a la herencia SOLO cuando no puede gestinar la clase Source class.\n      Ver los comentario m\u00e1s abajo }\n    inherited Assign(Source);\nend;\n\nprocedure TMyClassDescendant.Assign(Source: TPersistent);\nvar\n  SourceMyClassDescendant: TMyClassDescendant;\nbegin\n  if Source is TMyClassDescendant then\n  begin\n    SourceMyClassDescendant := TMyClassDescendant(Source);\n    MyString := SourceMyClassDescendant.MyString;\n    \/\/ Xxx := SourceMyClassDescendant.Xxx; \/\/ A\u00f1adir nuevos campos aqu\u00ed\n  end;\n\n  { Como  TMyClassDescendant tiene un antecesor, que ya sobre escribe \n    Assign (eb TMyClass.Assign), SIEMPRE llama a la herencia,\n    para permitir a TMyClass.Assign manejar los campos restantes.\n    Ver los comentarios m\u00e1s abajo para entender el razonamiento }\n  inherited Assign(Source);\nend;\n\nvar\n  C1, C2: TMyClass;\n  CD1, CD2: TMyClassDescendant;\nbegin\n  \/\/ test TMyClass.Assign\n  C1 := TMyClass.Create;\n  C2 := TMyClass.Create;\n  try\n    C1.MyInt := 666;\n    C2.Assign(C1);\n    WriteLn('C2 state: ', C2.MyInt);\n  finally\n    FreeAndNil(C1);\n    FreeAndNil(C2);\n  end;\n\n  \/\/ test TMyClassDescendant.Assign\n  CD1 := TMyClassDescendant.Create;\n  CD2 := TMyClassDescendant.Create;\n  try\n    CD1.MyInt := 44;\n    CD1.MyString := 'blah';\n    CD2.Assign(CD1);\n    WriteLn('CD2 state: ', CD2.MyInt, ' ', CD2.MyString);\n  finally\n    FreeAndNil(CD1);\n    FreeAndNil(CD2);\n  end;\nend.<\/pre><\/div>\n\n\n\n<p>A veces es m\u00e1s c\u00f3modo anular alternativamente el m\u00e9todo <em><code>AssignTo<\/code><\/em> en la clase de origen, en lugar de anular el m\u00e9todo <em><code>Assign<\/code><\/em> en la clase de destino.<\/p>\n\n\n\n<p>Tenga cuidado cuando llame a la herencia en la implementaci\u00f3n de Asignaci\u00f3n anulada. Hay dos situaciones:<\/p>\n\n\n\n<p><strong>Su clase es descendiente directa de la clase TPersistent. (O bien, no es un descendiente directo de TPersistent, pero ning\u00fan ancestro anul\u00f3 el m\u00e9todo Assign).<\/strong><\/p>\n\n\n\n<p>En este caso, su clase debe usar la palabra clave <em><code><em>inherited<\/em><\/code><\/em> (para llamar a <em><code>TPersistent.Assign<\/code><\/em>) solo si no puede manejar la asignaci\u00f3n en su c\u00f3digo.<\/p>\n\n\n\n<p><strong>Su clase desciende de alguna clase que ya ha anulado el m\u00e9todo Assign.<\/strong><\/p>\n\n\n\n<p>En este caso, su clase siempre debe usar la palabra clave <code><em>inherited<\/em><\/code> (para llamar al ancestro <em><code>Assign<\/code><\/em>). En general, llamar a m\u00e9todos heredados  anulados suele ser una buena idea.<\/p>\n\n\n\n<p>Para comprender el motivo detr\u00e1s de la regla anterior (cu\u00e1ndo debe llamar y cu\u00e1ndo no debe llamar a la herencia de la implementaci\u00f3n de <em><code>Assign<\/code><\/em>) y c\u00f3mo se relaciona con el m\u00e9todo <em><code>AssignTo<\/code><\/em>, veamos las implementaciones de <em><code>TPersistent.Assign<\/code><\/em> y <em><code>TPersistent.AssignTo<\/code><\/em>:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">procedure TPersistent.Assign(Source: TPersistent);\nbegin\n  if Source &lt;&gt; nil then\n    Source.AssignTo(Self)\n  else\n    raise EConvertError...\nend;\n\nprocedure TPersistent.AssignTo(Destination: TPersistent);\nbegin\n  raise EConvertError...\nend;<\/pre><\/div>\n\n\n\n<p>Nota: Esta no es la implementaci\u00f3n exacta de <em><code>TPersistent<\/code><\/em>. Copi\u00e9 el c\u00f3digo de la biblioteca est\u00e1ndar de FPC, pero luego lo simplifiqu\u00e9 para ocultar detalles sin importancia sobre el mensaje de excepci\u00f3n.<\/p>\n\n\n\n<p>Las conclusiones que se pueden sacar de lo anterior son:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Si no se anulan ni <em><code>Assign<\/code><\/em> ni <em><code>AssignTo<\/code><\/em>, llamarlos dar\u00e1 como resultado una excepci\u00f3n.<\/li>\n\n\n\n<li>Adem\u00e1s, tenga en cuenta que no hay c\u00f3digo en la implementaci\u00f3n de <em><code>TPersistent<\/code><\/em> que copia autom\u00e1ticamente todos los campos (o todos los campos publicados) de las clases. Es por eso que debe hacerlo usted mismo, anulando <em><code>Asignar<\/code><\/em> en todas las clases. Puede usar RTTI (informaci\u00f3n de tipo de tiempo de ejecuci\u00f3n) para eso, pero para casos simples, probablemente solo enumere los campos que se copiar\u00e1n manualmente.<\/li>\n<\/ul>\n\n\n\n<p>Cuando tiene una clase como <em><code>TApple<\/code><\/em>, su implementaci\u00f3n de <em><code>TApple.Assign<\/code><\/em> generalmente se ocupa de copiar campos que son espec\u00edficos de la clase <em><code>TApple<\/code><\/em> (no del ancestro de <em><code>TApple<\/code><\/em>, como <em><kbd>TFruit<\/kbd><\/em>). Por lo tanto, la implementaci\u00f3n de <em><code>TApple.Assign <\/code><\/em>generalmente verifica si la Fuente es <em><code>TApple<\/code><\/em> al principio, antes de copiar los campos relacionados con <em>Apple<\/em>. Luego, llama a la herencia para permitir que <em><code>TFruit<\/code><\/em> maneje el resto de los campos.<\/p>\n\n\n\n<p>Suponiendo que implement\u00f3 <em><code>TFruit.Assign <\/code><\/em>y <em><code>TApple.Assign<\/code><\/em> siguiendo el patr\u00f3n est\u00e1ndar (como se muestra en el ejemplo anterior), el efecto es as\u00ed:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Si pasa la instancia de <em><code>TApple<\/code><\/em> a <em><code>TApple.Assign<\/code><\/em>, funcionar\u00e1 y copiar\u00e1 todos los campos.<\/li>\n\n\n\n<li>Si pasa la instancia de <em><code>TOrange<\/code><\/em> a <em><code>TApple.Assign<\/code><\/em>, funcionar\u00e1 y solo copiar\u00e1 los campos comunes compartidos por <em><code>TOrange<\/code><\/em> y <em><code>TApple<\/code><\/em>. En otras palabras, los campos definidos en <em><code>TFruit<\/code><\/em><\/li>\n\n\n\n<li>Si pasa la instancia de <em>TWerewolf<\/em> a T<em><code>Apple.Assign<\/code><\/em>, generar\u00e1 una excepci\u00f3n (porque <em><code>TApple.Assign<\/code><\/em> llamar\u00e1 a <em><code>TFruit.Assign<\/code><\/em>, que llamar\u00e1 a <em><code>TPersistent.Assign<\/code><\/em>, que generar\u00e1 una excepci\u00f3n).<\/li>\n<\/ul>\n\n\n\n<p>Nota: Recuerde que al descender de <em><code>TPersistent<\/code><\/em>, se publica el especificador de visibilidad predeterminado, para permitir la transmisi\u00f3n de descendientes de <em><code>TPersistent<\/code><\/em>. No todos los tipos de campos y propiedades est\u00e1n permitidos en la secci\u00f3n publicada. Si obtiene errores relacionados con \u00e9l y no le importa la transmisi\u00f3n, simplemente cambie la visibilidad a p\u00fablico. Consulte los especificadores de visibilidad.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Funciones varias del lenguaje<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Rutinas locales (anidadas)<\/h3>\n\n\n\n<p>Dentro de una rutina m\u00e1s grande (funci\u00f3n, procedimiento, m\u00e9todo) puede definir una rutina auxiliar.<\/p>\n\n\n\n<p>La rutina local puede acceder libremente (leer y escribir) a todos los par\u00e1metros de un padre y a todas las variables locales del padre que se declararon sobre \u00e9l. Esto es muy poderoso. A menudo permite dividir rutinas largas en un par de peque\u00f1as sin mucho esfuerzo (ya que no tiene que pasar toda la informaci\u00f3n necesaria en los par\u00e1metros). Tenga cuidado de no abusar de esta caracter\u00edstica\u2009\u2014\u2009si muchas funciones anidadas usan (e incluso cambian) la misma variable del padre, el c\u00f3digo puede ser dif\u00edcil de seguir.<\/p>\n\n\n\n<p>Estos dos ejemplos son equivalentes:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">function SumOfSquares(const N: Integer): Integer;\n\n  function Square(const Value: Integer): Integer;\n  begin\n    Result := Value * Value;\n  end;\n\nvar\n  I: Integer;\nbegin\n  Result := 0;\n  for I := 0 to N do\n    Result := Result + Square(I);\nend;<\/pre><\/div>\n\n\n\n<p>Otra versi\u00f3n, donde dejamos que la rutina local Square acceda directamente a I:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">function SumOfSquares(const N: Integer): Integer;\nvar\n  I: Integer;\n\n  function Square: Integer;\n  begin\n    Result := I * I;\n  end;\n\nbegin\n  Result := 0;\n  for I := 0 to N do\n    Result := Result + Square;\nend;<\/pre><\/div>\n\n\n\n<p>Las rutinas locales pueden llegar a cualquier profundidad\u2009\u2014\u2009lo que significa que puede definir una rutina local dentro de otra rutina local. As\u00ed que puedes volverte loco (pero no te vuelvas loco demasiado, o el c\u00f3digo se volver\u00e1 ilegible :).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Callbacks (tambi\u00e9n conocidos como eventos, tambi\u00e9n conocidos como punteros a funciones, tambi\u00e9n conocidos como variables de procedimiento)<\/h3>\n\n\n\n<p>Permiten llamar a una funci\u00f3n de forma indirecta, a trav\u00e9s de una variable. La variable se puede asignar en tiempo de ejecuci\u00f3n para apuntar a cualquier funci\u00f3n con tipos de par\u00e1metros coincidentes y tipos de devoluci\u00f3n.<\/p>\n\n\n\n<p>La devoluci\u00f3n de llamada puede ser:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Normal, lo que significa que puede apuntar a cualquier rutina normal (no un m\u00e9todo, no local).<\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\n\nfunction Add(const A, B: Integer): Integer;\nbegin\n  Result := A + B;\nend;\n\nfunction Multiply(const A, B: Integer): Integer;\nbegin\n  Result := A * B;\nend;\n\ntype\n  TMyFunction = function (const A, B: Integer): Integer;\n\nfunction ProcessTheList(const F: TMyFunction): Integer;\nvar\n  I: Integer;\nbegin\n  Result := 1;\n  for I := 2 to 10 do\n    Result := F(Result, I);\nend;\n\nvar\n  SomeFunction: TMyFunction;\nbegin\n  SomeFunction := @Add;\n  WriteLn('1 + 2 + 3 ... + 10 = ', ProcessTheList(SomeFunction));\n\n  SomeFunction := @Multiply;\n  WriteLn('1 * 2 * 3 ... * 10 = ', ProcessTheList(SomeFunction));\nend.<\/pre><\/div>\n\n\n\n<p>Un m\u00e9todo: declarar con el objeto al final.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses\n  SysUtils;\n\ntype\n  TMyMethod = procedure (const A: Integer) of object;\n\n  TMyClass = class\n    CurrentValue: Integer;\n    procedure Add(const A: Integer);\n    procedure Multiply(const A: Integer);\n    procedure ProcessTheList(const M: TMyMethod);\n  end;\n\nprocedure TMyClass.Add(const A: Integer);\nbegin\n  CurrentValue := CurrentValue + A;\nend;\n\nprocedure TMyClass.Multiply(const A: Integer);\nbegin\n  CurrentValue := CurrentValue * A;\nend;\n\nprocedure TMyClass.ProcessTheList(const M: TMyMethod);\nvar\n  I: Integer;\nbegin\n  CurrentValue := 1;\n  for I := 2 to 10 do\n    M(I);\nend;\n\nvar\n  C: TMyClass;\nbegin\n  C := TMyClass.Create;\n  try\n    C.ProcessTheList(@C.Add);\n    WriteLn('1 + 2 + 3 ... + 10 = ', C.CurrentValue);\n\n    C.ProcessTheList(@C.Multiply);\n    WriteLn('1 * 2 * 3 ... * 10 = ', C.CurrentValue);\n  finally\n    FreeAndNil(C);\n  end;\nend.<\/pre><\/div>\n\n\n\n<p>Tenga en cuenta que no puede pasar procedimientos\/funciones globales como m\u00e9todos. Son incompatibles. Si tiene que proporcionar una devoluci\u00f3n de llamada de objeto, pero no desea crear una instancia de clase ficticia, puede pasar los m\u00e9todos de clase como m\u00e9todos.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">type\n  TMyMethod = function (const A, B: Integer): Integer of object;\n\n  TMyClass = class\n    class function Add(const A, B: Integer): Integer\n    class function Multiply(const A, B: Integer): Integer\n  end;\n\nvar\n  M: TMyMethod;\nbegin\n  M := @TMyClass(nil).Add;\n  M := @TMyClass(nil).Multiply;\nend;<\/pre><\/div>\n\n\n\n<p>Desafortunadamente, debe escribir feo @TMyClass(nil).Add en lugar de solo @TMyClass.Add.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Una (posiblemente) rutina local: declare with est\u00e1 anidada al final, y aseg\u00farese de usar la directiva {$modeswitch nestedprocvars} para el c\u00f3digo. Estos van de la mano con las rutinas locales (anidadas).<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Funciones anonimas (Anonymous functions)<\/h3>\n\n\n\n<p>Delphi y las versiones nuevas de FPC (&gt;= 3.3.1) soportan funciones an\u00f3nimas (anynomous functions).<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:default decode:true \">{ Example of Map, ForEach methods and processing list with anonymous functions. }\n\n{$ifdef FPC}\n  {$mode objfpc}{$H+}{$J-}\n  {$modeswitch functionreferences}\n  {$modeswitch anonymousfunctions}\n{$endif}\n{$apptype CONSOLE}\n\nuses SysUtils, Generics.Collections;\n\ntype\n  { Nota sobre la definici\u00f3n de TIntMapFunc y TIntMapProc a continuaci\u00f3n, \u00bfcu\u00e1l usar?\n\nEn resumen, usa \"reference to\". Puedes asignarles funciones an\u00f3nimas fiablemente tanto en Delphi como en FPC.\n\nCon Delphi 12.1, solo la versi\u00f3n con \"reference to\" se compilar\u00e1.\n\nCon FPC 3.3.1, tambi\u00e9n se compilar\u00e1n otras variantes.\nPuedes asignar funciones an\u00f3nimas a cualquiera de ellas.\nAs\u00ed que, si solo apuntas a FPC, puedes decidir qu\u00e9 versi\u00f3n usar\nbas\u00e1ndote en lo que quieres asignarles *aparte* de funciones an\u00f3nimas:\n\n- La primera versi\u00f3n (sin \"of object\", sin \"reference to\")\n  permite almacenar una referencia a una funci\u00f3n global,\n\n- La segunda (con \"of object\")\n  permite almacenar una referencia a un m\u00e9todo de un objeto,\n\n- La tercera (con \"reference to\") es la m\u00e1s universal,\n  permite muchas cosas --\n  ver https:\/\/forum.lazarus.freepascal.org\/index.php?topic=59468.0 .\n\n  }\n\n  TIntMapFunc =\n    \/\/function(const Index, Item: Integer): Integer;\n    \/\/function(const Index, Item: Integer): Integer of object;\n    reference to function(const Index, Item: Integer): Integer;\n  TIntMapProc =\n    \/\/procedure(const Index, Item: Integer);\n    \/\/procedure(const Index, Item: Integer) of object;\n    reference to procedure(const Index, Item: Integer);\n\n  TMyInts = class({$ifdef FPC}specialize{$endif} TList&lt;Integer&gt;)\n  { Cambia cada elemento un la lista usando AFunc}\n    procedure Map(const AFunc: TIntMapFunc);\n   {Llama AProc por cada iten en la lista}\n    procedure ForEach(const AProc: TIntMapProc);\n  end;\n\nprocedure TMyInts.Map(const AFunc: TIntMapFunc);\nvar\n  Index: Integer;\nbegin\n  for Index := 0 to Count - 1 do\n    Items[Index] := AFunc(Index, Items[Index]);\nend;\n\nprocedure TMyInts.ForEach(const AProc: TIntMapProc);\nvar\n  Index: Integer;\nbegin\n  for Index := 0 to Count - 1 do\n    AProc(Index, Items[Index]);\nend;\n\nvar\n  MyList: TMyInts;\n  I: Integer;\n  F: TIntMapFunc;\nbegin\n  MyList := TMyInts.Create;\n  try\n    for I := 0 to 10 do\n      MyList.Add(I);\n\n    F := function(const Index, Item: Integer): Integer\n      begin\n        Result := Item + 1;\n      end;\n    \/\/ effectively this increases all numbers on the list by 3\n    MyList.Map(F);\n    MyList.Map(F);\n    MyList.Map(F);\n\n    \/\/ change all items to their squares\n    MyList.Map(function(const Index, Item: Integer): Integer\n      begin\n        Result := Item * Item;\n      end);\n\n    \/\/ print all items\n    MyList.ForEach(procedure(const Index, Item: Integer)\n      begin\n        WriteLn('Index: ', Index, ', Item: ', Item);\n      end);\n  finally FreeAndNil(MyList) end;\nend.<\/pre><\/div>\n\n\n\n<p>M\u00e1s informaci\u00f3n:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Documentaci\u00f3n deDelphi : <a href=\"https:\/\/docwiki.embarcadero.com\/RADStudio\/Sydney\/en\/Anonymous_Methods_in_Delphi\">https:\/\/docwiki.embarcadero.com\/RADStudio\/Sydney\/en\/Anonymous_Methods_in_Delphi<\/a><\/li>\n\n\n\n<li>Foro de FPC : <a href=\"https:\/\/forum.lazarus.freepascal.org\/index.php\/topic,59468.0.html\">https:\/\/forum.lazarus.freepascal.org\/index.php\/topic,59468.0.html<\/a><\/li>\n\n\n\n<li>Registro de cambios FPC: <a href=\"https:\/\/wiki.freepascal.org\/FPC_New_Features_Trunk#Support_for_Function_References_and_Anonymous_Functions\">https:\/\/wiki.freepascal.org\/FPC_New_Features_Trunk#Support_for_Function_References_and_Anonymous_Functions<\/a><\/li>\n<\/ul>\n\n\n\n<p>Para obtener  FPC 3.3.1, recomendamos usar FpcUpDeluxe: <a href=\"https:\/\/castle-engine.io\/fpcupdeluxe\">https:\/\/castle-engine.io\/fpcupdeluxe<\/a> .<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Gen\u00e9ricos<\/h3>\n\n\n\n<p>Una poderosa caracter\u00edstica de cualquier lenguaje moderno. La definici\u00f3n de algo (t\u00edpicamente, de una clase) se puede parametrizar con otro tipo. El ejemplo m\u00e1s t\u00edpico es cuando necesitas crear un contenedor (una lista, diccionario, \u00e1rbol, gr\u00e1fico\u2026\u200b): puedes definir una lista de tipo T, y luego especializarla para obtener instant\u00e1neamente una lista de enteros, una lista de cadenas , una lista de <em><code>TMyRecord<\/code><\/em>, etc.<\/p>\n\n\n\n<p>Los gen\u00e9ricos en Pascal funcionan de forma muy similar a los gen\u00e9ricos en C++. Lo que significa que se \u00abexpanden\u00bb en el momento de la especializaci\u00f3n, un poco como las macros (pero mucho m\u00e1s seguras que las macros; por ejemplo, los identificadores se resuelven en el momento de la definici\u00f3n gen\u00e9rica, no en la especializaci\u00f3n, por lo que no puede \u00abinyectar\u00bb nada inesperado). comportamiento al especializar el gen\u00e9rico). En efecto, esto significa que son muy r\u00e1pidos (pueden optimizarse para cada tipo en particular) y funcionan con tipos de cualquier tama\u00f1o. Puede usar un tipo primitivo (entero, flotante), as\u00ed como un registro, as\u00ed como una clase al especializar un gen\u00e9rico.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses\n  SysUtils;\n\ntype\n  generic TMyCalculator&lt;T&gt; = class\n    Value: T;\n    procedure Add(const A: T);\n  end;\n\nprocedure TMyCalculator.Add(const A: T);\nbegin\n  Value := Value + A;\nend;\n\ntype\n  TMyFloatCalculator = specialize TMyCalculator&lt;Single&gt;;\n  TMyStringCalculator = specialize TMyCalculator&lt;string&gt;;\n\nvar\n  FloatCalc: TMyFloatCalculator;\n  StringCalc: TMyStringCalculator;\nbegin\n  FloatCalc := TMyFloatCalculator.Create;\n  try\n    FloatCalc.Add(3.14);\n    FloatCalc.Add(1);\n    WriteLn('FloatCalc: ', FloatCalc.Value:1:2);\n  finally\n    FreeAndNil(FloatCalc);\n  end;\n\n  StringCalc := TMyStringCalculator.Create;\n  try\n    StringCalc.Add('something');\n    StringCalc.Add(' more');\n    WriteLn('StringCalc: ', StringCalc.Value);\n  finally\n    FreeAndNil(StringCalc);\n  end;\nend.<\/pre><\/div>\n\n\n\n<p>Los gen\u00e9ricos no se limitan a las clases, tambi\u00e9n puede tener funciones y procedimientos gen\u00e9ricos:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses\n  SysUtils;\n\n{ Note: this example requires FPC 3.1.1 (will not compile with FPC 3.0.0 or older). }\n\ngeneric function Min&lt;T&gt;(const A, B: T): T;\nbegin\n  if A &lt; B then\n    Result := A else\n    Result := B;\nend;\n\nbegin\n  WriteLn('Min (1, 0): ', specialize Min&lt;Integer&gt;(1, 0));\n  WriteLn('Min (3.14, 5): ', specialize Min&lt;Single&gt;(3.14, 5):1:2);\n  WriteLn('Min (''a'', ''b''): ', specialize Min&lt;string&gt;('a', 'b'));\nend.<\/pre><\/div>\n\n\n\n<p>Consulte tambi\u00e9n los Contenedores (listas, diccionarios) que usan gen\u00e9ricos sobre clases est\u00e1ndar importantes que usan gen\u00e9ricos.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Sobrecarga<\/h3>\n\n\n\n<p>Se permiten m\u00e9todos (y funciones y procedimientos globales) con el mismo nombre, siempre que tengan par\u00e1metros diferentes. En tiempo de compilaci\u00f3n, el compilador detecta cu\u00e1l desea usar, sabiendo los par\u00e1metros que pasa.<\/p>\n\n\n\n<p>De forma predeterminada, la sobrecarga utiliza el enfoque FPC, lo que significa que todos los m\u00e9todos en un espacio de nombres dado (una clase o una unidad) son iguales y ocultan los otros m\u00e9todos en espacios de nombres con menos prioridad. Por ejemplo, si define una clase con los m\u00e9todos Foo(Integer) y Foo(string), y desciende de una clase con el m\u00e9todo Foo(Float), entonces los usuarios de su nueva clase no podr\u00e1n acceder al m\u00e9todo Foo( Float) f\u00e1cilmente (todav\u00eda pueden &#8212; si encasillan la clase a su tipo de antepasado). Para superar esto, utilice la palabra clave de sobrecarga.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Preprocesado<\/h3>\n\n\n\n<p>Puede usar directivas de preprocesador simples para:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>compilaci\u00f3n condicional (c\u00f3digo dependiendo de la plataforma, o algunos modificadores personalizados)<\/li>\n\n\n\n<li>incluir un archivo en otro<\/li>\n\n\n\n<li>tambi\u00e9n puede utilizar macros sin par\u00e1metros.<\/li>\n<\/ul>\n\n\n\n<p>Tenga en cuenta que no se permiten macros con par\u00e1metros. En general, debe evitar usar el preprocesador\u2026 a menos que est\u00e9 realmente justificado. El procesamiento previo ocurre antes del an\u00e1lisis, lo que significa que puede \u00abromper\u00bb la sintaxis normal del lenguaje Pascal. Esta es una caracter\u00edstica poderosa, pero tambi\u00e9n algo sucia.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nunit PreprocessorStuff;\ninterface\n\n{$ifdef FPC}\n{ This is only defined when compiled by FPC, not other compilers (like Delphi). }\nprocedure Foo;\n{$endif}\n\n{ Define a NewLine constant. Here you can see how the normal syntax of Pascal\n  is \"broken\" by preprocessor directives. When you compile on Unix\n  (includes Linux, Android, macOS), the compiler sees this:\n\n    const NewLine = #10;\n\n  When you compile on Windows, the compiler sees this:\n\n    const NewLine = #13#10;\n\n  On other operating systems, the code will fail to compile,\n  because a compiler sees this:\n\n    const NewLine = ;\n\n  It's a *good* thing that the compilation fails in this case -- if you\n  will have to port the program to an OS that is not Unix, not Windows,\n  you will be reminded by a compiler to choose the newline convention\n  on that system. }\n\nconst\n  NewLine =\n    {$ifdef UNIX} #10 {$endif}\n    {$ifdef MSWINDOWS} #13#10 {$endif} ;\n\n{$define MY_SYMBOL}\n\n{$ifdef MY_SYMBOL}\nprocedure Bar;\n{$endif}\n\n{$define CallingConventionMacro := unknown}\n{$ifdef UNIX}\n  {$define CallingConventionMacro := cdecl}\n{$endif}\n{$ifdef MSWINDOWS}\n  {$define CallingConventionMacro := stdcall}\n{$endif}\nprocedure RealProcedureName; CallingConventionMacro; external 'some_external_library';\n\nimplementation\n\n{$include some_file.inc}\n\/\/ $I is just a shortcut for $include\n{$I some_other_file.inc}\n\nend.<\/pre><\/div>\n\n\n\n<p>Los archivos de inclusi\u00f3n tienen com\u00fanmente la extensi\u00f3n .inc y se usan para dos prop\u00f3sitos:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>El archivo de inclusi\u00f3n solo puede contener otras directivas del compilador, que \u00abconfiguran\u00bb su c\u00f3digo fuente. Por ejemplo, podr\u00eda crear un archivo myconfig.inc con estos contenidos:<\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}\n{$H+}\n{$J-}\n{$modeswitch advancedrecords}\n{$ifndef VER3}\n  {$error This code can only be compiled using FPC version at least 3.x.}\n{$endif}\n<\/pre><\/div>\n\n\n\n<p>Ahora puede incluir este archivo usando {$I myconfig.inc} en todas sus fuentes.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>El otro uso com\u00fan es dividir una unidad grande en muchos archivos, y al mismo tiempo mantenerla en una sola unidad en lo que respecta a las reglas del idioma. No abuse de esta t\u00e9cnica\u2009\u2014\u2009su primer instinto debe ser dividir una sola unidad en m\u00faltiples unidades, no dividir una sola unidad en m\u00faltiples archivos de inclusi\u00f3n. Sin embargo, esta es una t\u00e9cnica \u00fatil.\n<ol class=\"wp-block-list\">\n<li>Permite evitar la \u00abexplosi\u00f3n\u00bb del n\u00famero de unidades, al mismo tiempo que mantiene cortos los archivos de c\u00f3digo fuente. Por ejemplo, puede ser mejor tener una sola unidad con \u00abcontroles de interfaz de usuario de uso com\u00fan\u00bb que crear una unidad para cada clase de control de interfaz de usuario, ya que este \u00faltimo enfoque har\u00eda que la cl\u00e1usula t\u00edpica de \u00abusos\u00bb fuera larga (ya que un c\u00f3digo de interfaz de usuario t\u00edpico dependen de un par de clases de interfaz de usuario). Pero colocar todas estas clases de interfaz de usuario en un solo archivo myunit.pas lo convertir\u00eda en un archivo largo, dif\u00edcil de navegar, por lo que dividirlo en varios archivos de inclusi\u00f3n puede tener sentido.<\/li>\n\n\n\n<li>Permite tener una interfaz de unidad multiplataforma con implementaci\u00f3n dependiente de la plataforma f\u00e1cilmente. B\u00e1sicamente puedes hacer<\/li>\n<\/ol>\n<\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$ifdef UNIX} {$I my_unix_implementation.inc} {$endif}\n{$ifdef MSWINDOWS} {$I my_windows_implementation.inc} {$endif}<\/pre><\/div>\n\n\n\n<p>A veces, esto es mejor que escribir un c\u00f3digo largo con muchos {$ifdef UNIX}, {$ifdef MSWINDOWS} mezclados con c\u00f3digo normal (declaraciones de variables, implementaci\u00f3n de rutinas). El c\u00f3digo es m\u00e1s legible de esta manera. Incluso puede usar esta t\u00e9cnica de manera m\u00e1s agresiva, usando la opci\u00f3n de l\u00ednea de comandos -Fi de FPC para incluir algunos subdirectorios solo para plataformas espec\u00edficas. Luego puede tener muchas versiones del archivo de inclusi\u00f3n {$I my platform_specific_implementation.inc} y simplemente incluirlas, permitiendo que el compilador encuentre la versi\u00f3n correcta.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Registros<\/h3>\n\n\n\n<p>Record es solo un contenedor para otras variables. Es como una clase mucho m\u00e1s simplificada: no hay herencia ni m\u00e9todos virtuales. Es como una estructura en lenguajes tipo C<\/p>\n\n\n\n<p>Si usa la directiva {$modeswitch advancedrecords}, los registros pueden tener m\u00e9todos y especificadores de visibilidad. En general, las caracter\u00edsticas del idioma que est\u00e1n disponibles para las clases y que no rompen el dise\u00f1o de memoria predecible simple de un registro, son posibles.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\n{$modeswitch advancedrecords}\ntype\n  TMyRecord = record\n  public\n    I, Square: Integer;\n    procedure WriteLnDescription;\n  end;\n\nprocedure TMyRecord.WriteLnDescription;\nbegin\n  WriteLn('Square of ', I, ' is ', Square);\nend;\n\nvar\n  A: array [0..9] of TMyRecord;\n  R: TMyRecord;\n  I: Integer;\nbegin\n  for I := 0 to 9 do\n  begin\n    A[I].I := I;\n    A[I].Square := I * I;\n  end;\n\n  for R in A do\n    R.WriteLnDescription;\nend.<\/pre><\/div>\n\n\n\n<p>En el Object Pascal moderno, su primer instinto deber\u00eda ser dise\u00f1ar una clase, no un registro, porque las clases est\u00e1n repletas de funciones \u00fatiles, como constructores y herencia.<\/p>\n\n\n\n<p>Pero los registros siguen siendo muy \u00fatiles cuando necesita velocidad o un dise\u00f1o de memoria predecible:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Los registros no tienen ning\u00fan constructor o destructor. Simplemente define una variable de un tipo de registro. Tiene contenidos indefinidos (basura de memoria) al principio (excepto los tipos administrados autom\u00e1ticamente, como cadenas; se garantiza que se inicializar\u00e1n para estar vac\u00edos y se finalizar\u00e1n para liberar el recuento de referencias). Por lo tanto, debe tener m\u00e1s cuidado cuando se trata de registros, pero le brinda cierta ganancia de rendimiento.<\/li>\n\n\n\n<li>Las matrices de registros son muy lineales en la memoria, por lo que son compatibles con la memoria cach\u00e9.<\/li>\n\n\n\n<li>El dise\u00f1o de la memoria de los registros (tama\u00f1o, relleno entre campos) est\u00e1 claramente definido en algunas situaciones: cuando solicita el dise\u00f1o C o cuando utiliza un registro empaquetado. Esto es \u00fatil:\n<ul class=\"wp-block-list\">\n<li>para comunicarse con bibliotecas escritas en otros lenguajes de programaci\u00f3n, cuando exponen una API basada en registros<\/li>\n\n\n\n<li>para leer y escribir archivos binarios<\/li>\n\n\n\n<li>para hacer trucos sucios de bajo nivel (como encasillar inseguro un tipo a otro, ser consciente de su representaci\u00f3n de memoria).<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Los registros tambi\u00e9n pueden tener partes de casos, que funcionan como uniones en lenguajes similares a C. Permiten tratar la misma pieza de memoria como de un tipo diferente, seg\u00fan sus necesidades. Como tal, esto permite una mayor eficiencia de la memoria en algunos casos. Y permite m\u00e1s trucos inseguros sucios y de bajo nivel \ud83d\ude42<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"> Objetos al estilo antiguo<\/h3>\n\n\n\n<p>En los viejos tiempos, Turbo Pascal introdujo otra sintaxis para la funcionalidad de clase, utilizando la palabra clave de objeto. Es algo as\u00ed como una mezcla entre el concepto de un disco y una clase moderna.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Los objetos de estilo antiguo se pueden asignar\/liberar, y durante esa operaci\u00f3n puede llamar a su constructor\/destructor.<\/li>\n\n\n\n<li>Pero tambi\u00e9n pueden declararse y usarse simplemente, como registros. Un registro simple o un tipo de objeto no es una referencia (puntero) a algo, son simplemente los datos. Esto los hace c\u00f3modos para datos peque\u00f1os, donde la asignaci\u00f3n de llamadas \/ gratis ser\u00eda molesta.<\/li>\n\n\n\n<li>Los objetos de estilo antiguo ofrecen herencia y m\u00e9todos virtuales, aunque con peque\u00f1as diferencias con las clases modernas. Tenga cuidado\u2009\u2014\u2009suceder\u00e1n cosas malas si intenta usar un objeto sin llamar a su constructor, y el objeto tiene m\u00e9todos virtuales.<\/li>\n<\/ul>\n\n\n\n<p>Se desaconseja utilizar los objetos de estilo antiguo en la mayor\u00eda de los casos. Las clases modernas proporcionan mucha m\u00e1s funcionalidad. Y cuando sea necesario, los registros (incluidos los registros avanzados) se pueden utilizar para el rendimiento. Estos conceptos suelen ser una mejor idea que los objetos de estilo antiguo.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Punteros<\/h3>\n\n\n\n<p>Puede crear un puntero a cualquier otro tipo. El puntero para escribir TMyRecord se declara como ^TMyRecord y, por convenci\u00f3n, se llama PMyRecord. Este es un ejemplo tradicional de una lista enlazada de enteros usando registros:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">type\n  PMyRecord = ^TMyRecord;\n  TMyRecord = record\n    Value: Integer;\n    Next: PMyRecord;\n  end;<\/pre><\/div>\n\n\n\n<p>Tenga en cuenta que la definici\u00f3n es recursiva (el tipo PMyRecord se define mediante el tipo TMyRecord, mientras que TMyRecord se define mediante PMyRecord). Se permite definir un tipo puntero a un tipo a\u00fan no definido, siempre que se resuelva dentro del mismo bloque de tipo.<\/p>\n\n\n\n<p>Puede asignar y liberar punteros usando los m\u00e9todos New\/Dispose, o (m\u00e1s bajo nivel, no tipo seguro) m\u00e9todos GetMem\/FreeMem. Elimina la referencia del puntero (para acceder a las cosas se\u00f1aladas por) agrega el operador ^ (por ejemplo, MyInteger := MyPointerToInteger^). Para realizar la operaci\u00f3n inversa, que consiste en obtener un puntero de una variable existente, se antepone el operador @ (por ejemplo, MyPointerToInteger := @MyInteger).<\/p>\n\n\n\n<p>Tambi\u00e9n hay un tipo de puntero sin tipo, similar a void* en lenguajes tipo C. Es completamente inseguro y puede encasillarse en cualquier otro tipo de puntero.<\/p>\n\n\n\n<p>Recuerde que una instancia de clase tambi\u00e9n es, de hecho, un puntero, aunque no requiere ning\u00fan operador ^ o @ para usarlo. Una lista enlazada usando clases es ciertamente posible, ser\u00eda simplemente esto:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">type\n  TMyClass = class\n    Value: Integer;\n    Next: TMyClass;\n  end;<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Sobrecarga de operadores<\/h3>\n\n\n\n<p>Puede anular el significado de muchos operadores de idiomas, por ejemplo, para permitir la adici\u00f3n y multiplicaci\u00f3n de sus tipos personalizados. Como esto:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses\n  StrUtils;\n\noperator* (const S: string; const A: Integer): string;\nbegin\n  Result := DupeString(S, A);\nend;\n\nbegin\n  WriteLn('bla' * 10);\nend.<\/pre><\/div>\n\n\n\n<p>Tambi\u00e9n puede anular operadores en clases. Dado que generalmente crea nuevas instancias de sus clases dentro de la funci\u00f3n del operador, la persona que llama debe recordar liberar el resultado.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses\n  SysUtils;\n\ntype\n  TMyClass = class\n    MyInt: Integer;\n  end;\n\noperator* (const C1, C2: TMyClass): TMyClass;\nbegin\n  Result := TMyClass.Create;\n  Result.MyInt := C1.MyInt * C2.MyInt;\nend;\n\nvar\n  C1, C2: TMyClass;\nbegin\n  C1 := TMyClass.Create;\n  try\n    C1.MyInt := 12;\n    C2 := C1 * C1;\n    try\n      WriteLn('12 * 12 = ', C2.MyInt);\n    finally\n      FreeAndNil(C2);\n    end;\n  finally\n    FreeAndNil(C1);\n  end;\nend.<\/pre><\/div>\n\n\n\n<p>Tambi\u00e9n puede anular operadores en registros. Esto suele ser m\u00e1s f\u00e1cil que sobrecargarlos para las clases, ya que la persona que llama no tiene que lidiar con la gesti\u00f3n de la memoria.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses\n  SysUtils;\n\ntype\n  TMyRecord = record\n    MyInt: Integer;\n  end;\n\noperator* (const C1, C2: TMyRecord): TMyRecord;\nbegin\n  Result.MyInt := C1.MyInt * C2.MyInt;\nend;\n\nvar\n  R1, R2: TMyRecord;\nbegin\n  R1.MyInt := 12;\n  R2 := R1 * R1;\n  WriteLn('12 * 12 = ', R2.MyInt);\nend.<\/pre><\/div>\n\n\n\n<p>Para registros, se recomienda usar {$modeswitch advancedrecords} y anular operadores como operadores de clase dentro del registro. Esto permite utilizar clases gen\u00e9ricas que dependen de la existencia de alg\u00fan operador (como TFPGList, que depende de la disponibilidad del operador de igualdad) con dichos registros. De lo contrario, no se encontrar\u00eda la definici\u00f3n \u00abglobal\u00bb de un operador (no dentro del registro) (porque no est\u00e1 disponible en el c\u00f3digo que implementa TFPGList), y no podr\u00eda especializar una lista como special TFPGList.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\n{$modeswitch advancedrecords}\nuses\n  SysUtils, FGL;\n\ntype\n  TMyRecord = record\n    MyInt: Integer;\n    class operator+ (const C1, C2: TMyRecord): TMyRecord;\n    class operator= (const C1, C2: TMyRecord): boolean;\n  end;\n\nclass operator TMyRecord.+ (const C1, C2: TMyRecord): TMyRecord;\nbegin\n  Result.MyInt := C1.MyInt + C2.MyInt;\nend;\n\nclass operator TMyRecord.= (const C1, C2: TMyRecord): boolean;\nbegin\n  Result := C1.MyInt = C2.MyInt;\nend;\n\ntype\n  TMyRecordList = specialize TFPGList&lt;TMyRecord&gt;;\n\nvar\n  R, ListItem: TMyRecord;\n  L: TMyRecordList;\nbegin\n  L := TMyRecordList.Create;\n  try\n    R.MyInt := 1;   L.Add(R);\n    R.MyInt := 10;  L.Add(R);\n    R.MyInt := 100; L.Add(R);\n\n    R.MyInt := 0;\n    for ListItem in L do\n      R := ListItem + R;\n\n    WriteLn('1 + 10 + 100 = ', R.MyInt);\n  finally\n    FreeAndNil(L);\n  end;\nend.<\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Caracter\u00edsticas de las clases avanzadas<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Privado y estrictamente privado<\/h3>\n\n\n\n<p>El especificador de visibilidad privada (<code><em>private<\/em><\/code>) significa que el campo (o m\u00e9todo) no es accesible fuera de esta clase. Pero permite una excepci\u00f3n: todo el c\u00f3digo definido en la misma unidad puede romper esto y acceder a campos y m\u00e9todos privados. Un programador de C++ dir\u00eda que en Pascal todas las clases dentro de una sola unidad son amigas. Esto suele ser \u00fatil y no rompe la encapsulaci\u00f3n, ya que est\u00e1 limitado a una unidad.   <\/p>\n\n\n\n<p>Sin embargo, si crea unidades m\u00e1s grandes, con muchas clases (que no est\u00e1n estrechamente integradas entre s\u00ed), es m\u00e1s seguro usar la privacidad estricta (<code>s<em>trict private<\/em><\/code>). Significa que el campo (o m\u00e9todo) no es accesible fuera de este per\u00edodo de clase. Sin excepciones.  <\/p>\n\n\n\n<p>De manera similar, hay visibilidad protegida (<code><em>protected<\/em><\/code>)(visible para los descendientes o amigos en la misma unidad) y protecci\u00f3n estricta (<code><em>strict protected<\/em><\/code>)(visible para los descendientes, punto).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">M\u00e1s cosas dentro de clases y clases anidadas <\/h3>\n\n\n\n<p>Puede abrir una secci\u00f3n de constantes (<em><code>const<\/code><\/em>) o tipos (<em><code>type<\/code><\/em>) dentro de una clase. De esta manera, incluso puede definir una clase dentro de una clase. Los especificadores de visibilidad funcionan como siempre, en particular, la clase anidada puede ser privada (no visible para el mundo exterior), lo que suele ser \u00fatil.<\/p>\n\n\n\n<p>Tenga en cuenta que para declarar un campo despu\u00e9s de una constante o tipo, deber\u00e1 abrir un bloque <em><code>var<\/code><\/em>.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">type\n  TMyClass = class\n  private\n    type\n      TInternalClass = class\n        Velocity: Single;\n        procedure DoSomething;\n      end;\n    var\n      FInternalClass: TInternalClass;\n  public\n    const\n      DefaultVelocity = 100.0;\n    constructor Create;\n    destructor Destroy; override;\n  end;\n\nconstructor TMyClass.Create;\nbegin\n  inherited;\n  FInternalClass := TInternalClass.Create;\n  FInternalClass.Velocity := DefaultVelocity;\n  FInternalClass.DoSomething;\nend;\n\ndestructor TMyClass.Destroy;\nbegin\n  FreeAndNil(FInternalClass);\n  inherited;\nend;\n\n{ F\u00edjate que el la definici\u00f3n del m\u00e9todoslleva el prefijo \n  \"TMyClass.TInternalClass\" }\nprocedure TMyClass.TInternalClass.DoSomething;\nbegin\nend;<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">M\u00e9todos de clase<\/h3>\n\n\n\n<p>Estos son m\u00e9todos a los que puede llamar con una referencia de clase (<em><code>TMyClass<\/code><\/em>), no son necesariamente una instancia de una clase.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">type\n  TEnemy = class\n    procedure Kill;\n    class procedure KillAll;\n  end;\n\nvar\n  E: TEnemy;\nbegin\n  E := TEnemy.Create;\n  try\n    E.Kill;\n  finally FreeAndNil(E) end;\n  TEnemy.KillAll;\nend;<\/pre><\/div>\n\n\n\n<p>Tenga en cuenta que pueden ser virtuales\u2009\u2014\u2009tiene sentido, y a veces es muy \u00fatil, cuando se combinan con referencias de clase.<\/p>\n\n\n\n<p>Los m\u00e9todos de una clase tambi\u00e9n pueden estar limitados por los especificadores de visibilidad, como privado (<code><em>private<\/em><\/code>) o protegido (<code>protected<\/code>). Al igual que los m\u00e9todos regulares.<\/p>\n\n\n\n<p>Tenga en cuenta que un constructor siempre act\u00faa como un m\u00e9todo de una  clase cuando se llama de forma normal (<em><code>MyInstance := TMyClass.Create(\u2026\u200b);<\/code><\/em>). Aunque tambi\u00e9n es posible llamar a un constructor desde dentro de la propia clase, como un m\u00e9todo normal, y luego act\u00faa como un m\u00e9todo normal. Esta es una caracter\u00edstica \u00fatil para \u00abencadenar\u00bb constructores, cuando un constructor (por ejemplo, sobrecargado puede tomar un par\u00e1metro entero) hace alg\u00fan trabajo y luego llama a otro constructor (por ejemplo, sin par\u00e1metros).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Referencias de clase<\/h3>\n\n\n\n<p>La referencia de una clase le permite elegir la clase en tiempo de ejecuci\u00f3n, por ejemplo, para llamar a un m\u00e9todo de una clase o constructor sin conocer la clase exacta en tiempo de compilaci\u00f3n. Es un tipo declarado como clase de <code><em>TMyClass<\/em><\/code>.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">type\n  TMyClass = class(TComponent)\n  end;\n\n  TMyClass1 = class(TMyClass)\n  end;\n\n  TMyClass2 = class(TMyClass)\n  end;\n\n  TMyClassRef = class of TMyClass;\n\nvar\n  C: TMyClass;\n  ClassRef: TMyClassRef;\nbegin\n  \/\/ obviamente puede hacer esto:\n\n  C := TMyClass.Create(nil); FreeAndNil(C);\n  C := TMyClass1.Create(nil); FreeAndNil(C);\n  C := TMyClass2.Create(nil); FreeAndNil(C);\n\n  \/\/ Adem\u00e1s, usando referencias a una clase puede hacer esto:\n\n  ClassRef := TMyClass;\n  C := ClassRef.Create(nil); FreeAndNil(C);\n\n  ClassRef := TMyClass1;\n  C := ClassRef.Create(nil); FreeAndNil(C);\n\n  ClassRef := TMyClass2;\n  C := ClassRef.Create(nil); FreeAndNil(C);\nend;<\/pre><\/div>\n\n\n\n<p>Las referencias de una clase se pueden combinar con m\u00e9todos de clase virtual. Esto da un efecto similar al uso de clases con m\u00e9todos virtuales\u2009\u2014\u2009el m\u00e9todo real que se ejecutar\u00e1 se determina en tiempo de ejecuci\u00f3n.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">type\n  TMyClass = class(TComponent)\n    class procedure DoSomething; virtual; abstract;\n  end;\n\n  TMyClass1 = class(TMyClass)\n    class procedure DoSomething; override;\n  end;\n\n  TMyClass2 = class(TMyClass)\n    class procedure DoSomething; override;\n  end;\n\n  TMyClassRef = class of TMyClass;\n\nvar\n  C: TMyClass;\n  ClassRef: TMyClassRef;\nbegin\n  ClassRef := TMyClass1;\n  ClassRef.DoSomething;\n\n  ClassRef := TMyClass2;\n  ClassRef.DoSomething;\n\n  { Y esto ejecutar\u00e1 una excepci\u00f3n en tiempo de ejecuci\u00f3n,\n    ya que DoSomething es abstracto en en TMyClass. }\n  ClassRef := TMyClass;\n  ClassRef.DoSomething;\nend;<\/pre><\/div>\n\n\n\n<p>Si tiene una instancia y desea obtener una referencia a su clase (no la clase declarada, sino la clase descendiente final utilizada en su construcci\u00f3n), puede usar la propiedad <code><em>ClassType<\/em><\/code>. El tipo declarado de <em><code>ClassType<\/code><\/em> es <code><em>TClass<\/em><\/code>, que significa clase de <em><code>TObject<\/code><\/em>. A menudo, puede encasillarlo de manera segura en algo m\u00e1s espec\u00edfico, cuando sabe que la instancia es algo m\u00e1s espec\u00edfico que <em><code>TObject<\/code><\/em>.<\/p>\n\n\n\n<p>En particular, puede usar la referencia <em><code>ClassType<\/code><\/em> para llamar a m\u00e9todos virtuales, incluidos los constructores virtuales. Esto le permite crear un m\u00e9todo como <em><code>Clone<\/code><\/em> que construye una instancia de la clase de tiempo de ejecuci\u00f3n exacta del objeto actual. Puede combinarlo con <em><code>Cloning: TPersistent.Assign<\/code><\/em> para tener un m\u00e9todo que devuelva un clon reci\u00e9n construido de la instancia actual.<\/p>\n\n\n\n<p>Recuerda que solo funciona cuando el constructor de tu clase es virtual. Por ejemplo, se puede usar con los descendientes est\u00e1ndar de <em><code>TComponent<\/code><\/em>, ya que todos deben anular el constructor virtual <em><code>TComponent.Create(AOwner: TComponent)<\/code><\/em>.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">type\n  TMyClass = class(TComponent)\n    procedure Assign(Source: TPersistent); override;\n    function Clone(AOwner: TComponent): TMyClass;\n  end;\n\n  TMyClassRef = class of TMyClass;\n\nfunction TMyClass.Clone(AOwner: TComponent): TMyClass;\nbegin\n  \/\/ Esto siempre crea una instancia exacta de TMyClass\n  \/\/ Result := TMyClass.Create(AOwner);\n  \/\/ Esto, potencialmente, crea una instancia de descendiente de TMyClass\n  Result := TMyClassRef(ClassType).Create(AOwner);\n  Result.Assign(Self);\nend;<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">M\u00e9todos de una clase est\u00e1tica<\/h3>\n\n\n\n<p>Para comprender los m\u00e9todos de una clase est\u00e1ticos, debe comprender c\u00f3mo funcionan los m\u00e9todos de clase normales (descritos en las secciones anteriores). Internamente, los m\u00e9todos de clase normales reciben una referencia de una clase de su clase (se pasa a trav\u00e9s de un primer par\u00e1metro del m\u00e9todo oculto e impl\u00edcitamente agregado). Incluso se puede acceder a esta referencia de clase expl\u00edcitamente usando la palabra clave Self dentro del m\u00e9todo de clase. Por lo general, es algo bueno: esta referencia de clase le permite llamar a m\u00e9todos de clases virtuales (a trav\u00e9s de la tabla de m\u00e9todos virtuales de la clase).<\/p>\n\n\n\n<p>Si bien esto es bueno, hace que los m\u00e9todos de clase normales sean incompatibles cuando se asignan a un puntero de procedimiento global. Es decir, esto no compilar\u00e1:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\ntype\n  TMyCallback = procedure (A: Integer);\n\n  TMyClass = class\n    class procedure Foo(A: Integer);\n  end;\n\nclass procedure TMyClass.Foo(A: Integer);\nbegin\nend;\n\nvar\n  Callback: TMyCallback;\nbegin\n  \/\/ Error: TMyClass.Foo es compatible con TMyCallBack\n  Callback := @TMyClass(nil).Foo;\nend.<\/pre><\/div>\n\n\n\n<p>Nota: En el modo Delphi, podr\u00eda escribir <em><kbd><code>TMyClass<\/code><\/kbd><\/em>.Foo en lugar de un feo <code><em>TMyClass(nil).Foo<\/em><\/code> en el ejemplo anterior. Es cierto que T<code><em>MyClass.Foo<\/em><\/code> se ve mucho m\u00e1s elegante y el compilador tambi\u00e9n lo verifica mejor. Usar T<code><em>MyClass(nil).Foo<\/em><\/code> es un truco\u2026 desafortunadamente, es necesario (por ahora) en el modo ObjFpc que se presenta a lo largo de este libro.<\/p>\n\n\n\n<p>En cualquier caso, la asignaci\u00f3n de <em><code>TMyClass.Foo <\/code><\/em>a la devoluci\u00f3n de llamada anterior a\u00fan fallar\u00eda en el modo Delphi, exactamente por las mismas razones.<\/p>\n\n\n\n<p>El ejemplo anterior no se compila porque <em><code>Callback<\/code><\/em> es incompatible con el m\u00e9todo de la clase <code><em>Foo<\/em><\/code>. Y es incompatible porque internamente el m\u00e9todo de la clase tiene ese par\u00e1metro impl\u00edcito oculto especial para pasar una referencia de una clase.<\/p>\n\n\n\n<p>Una forma de corregir el ejemplo anterior es cambiar la definici\u00f3n de <code><em>TMyCallback<\/em><\/code>. Funcionar\u00e1 si se trata de una devoluci\u00f3n de la llamada de m\u00e9todo, declarada como <code><em>TMyCallback = procedimiento (A: Integer) of object;<\/em><\/code>. Pero a veces, no es deseable.<\/p>\n\n\n\n<p>Aqu\u00ed viene el m\u00e9todo de una clase est\u00e1tica. Es, en esencia, solo un procedimiento\/funci\u00f3n global, pero su espacio de nombres est\u00e1 limitado dentro de la clase. No tiene ninguna referencia de clase impl\u00edcita (y por lo tanto, no puede ser virtual y no puede llamar a m\u00e9todos de clase virtual). Pero el lado positivo, es compatible con las devoluciones de llamadas normales (sin objetos). As\u00ed que esto funcionar\u00e1:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\ntype\n  TMyCallback = procedure (A: Integer);\n\n  TMyClass = class\n    class procedure Foo(A: Integer); static;\n  end;\n\nclass procedure TMyClass.Foo(A: Integer);\nbegin\nend;\n\nvar\n  Callback: TMyCallback;\nbegin\n  Callback := @TMyClass.Foo;\nend.<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Propiedades de clase y variables<\/h3>\n\n\n\n<p>Una propiedad de una clase es una propiedad a la que se puede acceder a trav\u00e9s de una referencia de una clase (no necesita una instancia de clase).<\/p>\n\n\n\n<p>Es una analog\u00eda bastante directa de una propiedad regular (ver Propiedades). Para una propiedad de una clase, define un getter y\/o un setter. Pueden hacer referencia a una variable de clase o a un m\u00e9todo de clase est\u00e1tico.<\/p>\n\n\n\n<p>Una variable de una clase es, lo adivin\u00f3, como un campo normal, pero no necesita una instancia de clase para acceder a ella. En efecto, es como una variable global, pero con el espacio de nombres limitado a la clase contenedora. Se puede declarar dentro de la secci\u00f3n <em><code>class var<\/code><\/em> de la clase. Alternativamente, se puede declarar siguiendo la definici\u00f3n de campo normal con la palabra clave <code><em>static<\/em><\/code>.<\/p>\n\n\n\n<p>Y un m\u00e9todo de una clase est\u00e1tica es como un procedimiento\/funci\u00f3n global, pero con el espacio de nombres limitado a la clase contenedora. Para obtener m\u00e1s informaci\u00f3n sobre los m\u00e9todos de clase est\u00e1ticos en la secci\u00f3n anterior, consulte M\u00e9todos de clase est\u00e1ticos.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\ntype\n  TMyClass = class\n  strict private\n    \/\/ Alternative:\n    \/\/ FMyProperty: Integer; static;\n    class var\n      FMyProperty: Integer;\n    class procedure SetMyProperty(const Value: Integer); static;\n  public\n    class property MyProperty: Integer\n      read FMyProperty write SetMyProperty;\n  end;\n\nclass procedure TMyClass.SetMyProperty(const Value: Integer);\nbegin\n  Writeln('MyProperty cambia!');\n  FMyProperty := Value;\nend;\n\nbegin\n  TMyClass.MyProperty := 123;\n  Writeln('TMyClass.MyProperty is now ', TMyClass.MyProperty);\nend.<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Ayudantes de clase (Helpers)<\/h3>\n\n\n\n<p>El m\u00e9todo es solo un procedimiento o funci\u00f3n dentro de una clase. Desde el exterior de la clase, la llama con una sintaxis especial <em><code>MyInstance.MyMethod(\u2026\u200b)<\/code><\/em>. Despu\u00e9s de un tiempo te acostumbras a pensar que si quiero hacer una acci\u00f3n Acci\u00f3n en la instancia X, escribo <code><em>X.Action(\u2026\u200b)<\/em><\/code>.<\/p>\n\n\n\n<p>Pero a veces, necesita implementar algo que conceptualmente es una acci\u00f3n en la clase <em><code>TMyClass<\/code><\/em> sin modificar el c\u00f3digo fuente de <em><code>TMyClass<\/code><\/em>. A veces es porque no es su c\u00f3digo fuente y no quiere cambiarlo. A veces se debe a las dependencias\u2009\u2014\u2009agregar un m\u00e9todo como <em><code>Render<\/code><\/em> a una clase como <em><code>TMy3DObject<\/code><\/em> parece una idea sencilla, pero tal vez la implementaci\u00f3n base de la clase <code><em>TMy3DObject<\/em><\/code> deber\u00eda mantenerse independiente del c\u00f3digo de renderizado. Ser\u00eda mejor \u00abmejorar\u00bb una clase existente, agregarle funcionalidad sin cambiar su c\u00f3digo fuente.<\/p>\n\n\n\n<p>Una forma sencilla de hacerlo es crear un procedimiento global que tome una instancia de TMy3DObject como su primer par\u00e1metro.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">type\n  TMy3DObjectHelper = class helper for TMy3DObject\n    procedure Render(const Color: TColor);\n  end;\n\nprocedure TMy3DObjectHelper.Render(const Color: TColor);\nvar\n  I: Integer;\nbegin\n  {F\u00edjate que accedemos a ShapesCount, Aqu\u00ed, shaoe sin ning\u00fan calificativo}\n  for I := 0 to ShapesCount - 1 do\n    RenderMesh(Shape[I].Mesh, Color);\nend;<\/pre><\/div>\n\n\n\n<p>El concepto m\u00e1s general es \u00abtype helper\u00bb. Al usarlos, puede agregar m\u00e9todos incluso a tipos primitivos, como enteros o enumeraciones. Tambi\u00e9n puede agregar \u00abayudantes de registro\u00bb a (lo adivin\u00f3\u2026) registros. Consulte <a rel=\"noreferrer noopener\" href=\"http:\/\/lists.freepascal.org\/fpc-announce\/2013-February\/000587.html\" target=\"_blank\">http:\/\/lists.freepascal.org\/fpc-announce\/2013-February\/000587.html<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Constructores virtuales, destructores<\/h3>\n\n\n\n<p>El nombre del destructor siempre es <em><code>Destroy<\/code><\/em>, es virtual (ya que puede llamarlo sin conocer la clase exacta en tiempo de compilaci\u00f3n) y sin par\u00e1metros.<\/p>\n\n\n\n<p>El nombre del constructor es por convenci\u00f3n Create.<\/p>\n\n\n\n<p>Puede cambiar este nombre, aunque tenga cuidado con esto: si define <em><code>CreateMy<\/code><\/em>, siempre redefina tambi\u00e9n el nombre <em><code>Create<\/code><\/em>, de lo contrario, el usuario a\u00fan puede acceder al constructor <em><code>Create<\/code><\/em> del antepasado, sin pasar por su constructor <code><em>CreateMy<\/em><\/code>.<\/p>\n\n\n\n<p>En el <code><em>TObject<\/em><\/code> base no es virtual, y al crear descendientes eres libre de cambiar los par\u00e1metros. El nuevo constructor ocultar\u00e1 el constructor en el ancestro (nota: no ponga aqu\u00ed sobrecarga, a menos que quiera romperlo).<\/p>\n\n\n\n<p>En los descendientes de <em><code>TComponent<\/code><\/em>, debe anular su constructor <em><code>Create (AOwner: TComponent);<\/code><\/em>. Para la funcionalidad de transmisi\u00f3n (<em>streaming<\/em>), para crear una clase sin conocer su tipo en el momento de la compilaci\u00f3n, es muy \u00fatil tener constructores virtuales (consulte Referencias de una clase m\u00e1s arriba).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Una excepci\u00f3n en el constructor<\/h3>\n\n\n\n<p>\u00bfQu\u00e9 sucede si ocurre una excepci\u00f3n durante un constructor? La l\u00ednea:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">X := TMyClass.Create;<\/pre><\/div>\n\n\n\n<p>no se ejecuta hasta el final en este caso, no se puede asignar X, entonces, \u00bfqui\u00e9n limpiar\u00e1 despu\u00e9s de una clase parcialmente construida?<\/p>\n\n\n\n<p>La soluci\u00f3n de Object Pascal es que, en caso de que ocurra una excepci\u00f3n dentro de un constructor, se llama al destructor. Esta es una raz\u00f3n por la que su destructor debe ser robusto, lo que significa que deber\u00eda funcionar en cualquier circunstancia, incluso en una instancia de clase creada a medias. Por lo general, esto es f\u00e1cil si libera todo de forma segura, como FreeAndNil.<\/p>\n\n\n\n<p>Tambi\u00e9n tenemos que depender en tales casos de que se garantice que la memoria de la clase se ponga a cero justo antes de que se ejecute el c\u00f3digo del constructor. Entonces sabemos que al principio, todas las referencias de clase son nulas, todos los n\u00fameros enteros son 0 y as\u00ed sucesivamente.<\/p>\n\n\n\n<p>Entonces, a continuaci\u00f3n, funciona sin fugas de memoria:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses\n  SysUtils;\n\ntype\n  TGun = class\n  end;\n\n  TPlayer = class\n    Gun1, Gun2: TGun;\n    constructor Create;\n    destructor Destroy; override;\n  end;\n\nconstructor TPlayer.Create;\nbegin\n  inherited;\n  Gun1 := TGun.Create;\n  raise Exception.Create('\u00a1Elevando una excepci\u00f3n desde el constructor!');\n  Gun2 := TGun.Create;\nend;\n\ndestructor TPlayer.Destroy;\nbegin\n  { en caso que el constructor rompa, podemos tener  \n     Gun1 &lt;&gt; nil and Gun2 = nil now. Debemos gestionarlo\n    ...Actualmente en este caso, FreeAndNil, lo gestiona sin ning\u00fan\n   esfuerzo adicional, porque FreeAndNil comprueba si la instancia es Nil,\n  antes de llamar a su destructor.}\n  FreeAndNil(Gun1);\n  FreeAndNil(Gun2);\n  inherited;\nend;\n\nbegin\n  try\n    TPlayer.Create;\n  except\n    on E: Exception do\n      WriteLn('Capturada ' + E.ClassName + ': ' + E.Message);\n  end;\nend.<\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Interfaces<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Interfaces b\u00e1sicas (CORBA)<\/h3>\n\n\n\n<p>Una interfaz declara una API de la misma forma que una clase pero, a diferencia de estas, no define su<br>implementaci\u00f3n. Una clase s\u00f3lo puede tener una clase padre, pero puede implementar muchas interfaces.<br>Se puede hacer un cast de una clase a cualquiera de las interfaces que soporta y, de esta forma, llamar a<br>los m\u00e9todos a trav\u00e9s de esa interfaz. Esto permite tratar de forma uniforme a clases que no descienden<br>unas de otras pero que tienen una funcionalidad com\u00fan. Son \u00fatiles cuando una herencia simple de clase no<br>es suficiente para alcanzar la funcionalidad deseada.<br>Las interfaces CORBA en Object Pascal trabajan de forma muy parecida a las interfaces de Java<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>(<a href=\"https:\/\/docs.oracle.com\/javase\/tutorial\/java\/concepts\/interface.html\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/docs.oracle.com\/javase\/tutorial\/java\/concepts\/interface.html<\/a>) <\/li>\n\n\n\n<li>(<a href=\"https:\/\/msdn.microsoft.com\/en -us\/library\/ms173156.aspx\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/msdn.microsoft.com\/en -us\/library\/ms173156.aspx<\/a>).<\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\n{$interfaces corba}\n\nuses\n  SysUtils, Classes;\n\ntype\n  IMyInterface = interface\n  ['{79352612-668B-4E8C-910A-26975E103CAC}']\n    procedure Shoot;\n  end;\n\n  TMyClass1 = class(IMyInterface)\n    procedure Shoot;\n  end;\n\n  TMyClass2 = class(IMyInterface)\n    procedure Shoot;\n  end;\n\n  TMyClass3 = class\n    procedure Shoot;\n  end;\n\nprocedure TMyClass1.Shoot;\nbegin\n  WriteLn('TMyClass1.Shoot');\nend;\n\nprocedure TMyClass2.Shoot;\nbegin\n  WriteLn('TMyClass2.Shoot');\nend;\n\nprocedure TMyClass3.Shoot;\nbegin\n  WriteLn('TMyClass3.Shoot');\nend;\n\nprocedure UseThroughInterface(I: IMyInterface);\nbegin\n  Write('Disparando... ');\n  I.Shoot;\nend;\n\nvar\n  C1: TMyClass1;\n  C2: TMyClass2;\n  C3: TMyClass3;\nbegin\n  C1 := TMyClass1.Create;\n  C2 := TMyClass2.Create;\n  C3 := TMyClass3.Create;\n  try\n    if C1 is IMyInterface then\n      UseThroughInterface(C1 as IMyInterface);\n    if C2 is IMyInterface then\n      UseThroughInterface(C2 as IMyInterface);\n    \/\/ La interface \"C3\", m\u00e1s abajo, es falsa,\n    \/\/ as\u00ed \"UseThroughInterface(C3 as IMyInterface)\" no se ejecutar\u00e1.\n    if C3 is IMyInterface then\n      UseThroughInterface(C3 as IMyInterface);\n  finally\n    FreeAndNil(C1);\n    FreeAndNil(C2);\n    FreeAndNil(C3);\n  end;\nend.<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Tipos de interfaces: CORBA y COM<\/h3>\n\n\n\n<h3 class=\"wp-block-heading\"><br>\u00bfPorqu\u00e9 las interfaces del ejemplo anterior se denominan \u201cCORBA\u201d?<\/h3>\n\n\n\n<p><br>La denominaci\u00f3n <strong>CORBA<\/strong> no es muy afortunada. Un nombre m\u00e1s adecuado ser\u00eda interfaces desnudas o b\u00e1sicas (<strong>bare interfaces<\/strong>), dado que estas interfaces son una \u201c<em>caracter\u00edstica b\u00e1sica del lenguaje<\/em>\u201d.<br>Util\u00edzalas cuando desees asimilar varias clases a la misma interfaz, dado que comparten la misma API.<\/p>\n\n\n\n<p><br>A pesar de que estas interfaces pueden utilizarse con <strong>la tecnolog\u00eda CORBA (Common Object Request Broker Architecture)<\/strong> (ver informaci\u00f3n sobre CORBA en Wikipedia), no est\u00e1n ligadas a esta tecnolog\u00eda en<br>modo alguno.<\/p>\n\n\n\n<p><strong>\u00bfSe necesita la declaraci\u00f3n {$interfaces corba}?<\/strong><\/p>\n\n\n\n<p> S\u00ed, porque por defecto creas interfaces COM. Esto se puede indicar expl\u00edcitamente diciendo {$interfaces com}, pero por lo general no es necesario ya que es el estado predeterminado.  <\/p>\n\n\n\n<p>Y no aconsejo usar interfaces COM, especialmente si est\u00e1 buscando algo equivalente a las interfaces de otros lenguajes de programaci\u00f3n. Las interfaces CORBA en Pascal son exactamente lo que espera si busca algo equivalente a las interfaces en C# y Java. Mientras que las interfaces COM traen caracter\u00edsticas adicionales que posiblemente no desee.<\/p>\n\n\n\n<p>Tenga en cuenta que la declaraci\u00f3n<code><em> {$interfaces xxx}<\/em><\/code> solo afecta a las interfaces que no tienen ning\u00fan ancestro expl\u00edcito (solo la palabra clave interface, no <em><code>interface(ISomeAncestor)<\/code><\/em>). Cuando una interfaz tiene un ancestro, tiene el mismo tipo que el ancestro, independientemente de la declaraci\u00f3n <em><code>{$interfaces xxx}<\/code><\/em>.<\/p>\n\n\n\n<p><strong>\u00bfQu\u00e9 son las interfaces COM?<\/strong><\/p>\n\n\n\n<p>La interfaz COM es sin\u00f3nimo de una interfaz que desciende de una interfaz especial <em><code>IUnknown<\/code><\/em>. Descendente de <code><em>IUnknown<\/em><\/code>:<\/p>\n\n\n\n<p>Requiere que sus clases definan los m\u00e9todos <em><code>_AddRef<\/code> <\/em>y <em><code>_ReleaseRef<\/code><\/em>. La implementaci\u00f3n adecuada de estos m\u00e9todos puede administrar la vida \u00fatil de sus objetos utilizando el recuento de referencias.      <\/p>\n\n\n\n<p>Agrega el m\u00e9todo <em><code>QueryInterface<\/code><\/em>. <\/p>\n\n\n\n<p>Permite interactuar con la tecnolog\u00eda COM (Component Object Model).<\/p>\n\n\n\n<p><strong>\u00bfPor qu\u00e9 aconseja no utilizar las interfaces COM?<\/strong><\/p>\n\n\n\n<p>Debido a que las interfaces COM \u00abenredan\u00bb dos caracter\u00edsticas que deber\u00edan no estar relacionadas (ortogonales) en mi opini\u00f3n: herencia m\u00faltiple y conteo de referencias. Otros lenguajes de programaci\u00f3n usan correctamente conceptos separados para estas dos caracter\u00edsticas. Para ser claros: el conteo de referencias, que proporciona una gesti\u00f3n autom\u00e1tica de la memoria (en situaciones simples, es decir, sin ciclos), es un concepto muy \u00fatil. Pero enredar esta caracter\u00edstica con interfaces (en lugar de convertirlas en caracter\u00edsticas ortogonales) no es limpio a mis ojos. Definitivamente no coincide con mis casos de uso.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li> veces quiero enviar mis clases (que de otro modo no estar\u00edan relacionadas) a una interfaz com\u00fan.     <\/li>\n\n\n\n<li> A veces quiero administrar la memoria usando el enfoque de conteo de referencias.      <\/li>\n\n\n\n<li>Quiz\u00e1s alg\u00fan d\u00eda quiera interactuar con la tecnolog\u00eda COM.<\/li>\n<\/ul>\n\n\n\n<p>Pero todas estas son necesidades separadas y no relacionadas. Enredarlos en una caracter\u00edstica de un solo idioma es contraproducente en mi experiencia. Causa problemas reales:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Si quiero la caracter\u00edstica de enviar clases a una API de interfaz com\u00fan, pero no quiero el mecanismo de conteo de referencias (quiero liberar objetos manualmente), entonces las interfaces COM son problem\u00e1ticas. Incluso cuando el conteo de referencias est\u00e1 deshabilitado por una implementaci\u00f3n especial de _AddRef y _ReleaseRef, a\u00fan debe tener cuidado de nunca tener una referencia de interfaz temporal colgada, despu\u00e9s de haber liberado la instancia de clase. M\u00e1s detalles al respecto en la siguiente secci\u00f3n.  <\/li>\n\n\n\n<li>Si quiero la funci\u00f3n de conteo de referencias, pero no necesito una jerarqu\u00eda de interfaz para representar algo diferente a la jerarqu\u00eda de clases, entonces tengo que duplicar la API de mis clases en las interfaces. Creando as\u00ed una sola interfaz para cada clase. Esto es contraproducente. Preferir\u00eda tener punteros inteligentes como una caracter\u00edstica de idioma separada, no enredada con las interfaces (y afortunadamente, est\u00e1 llegando :).<\/li>\n<\/ul>\n\n\n\n<p>Es por eso que aconsejo usar interfaces de estilo CORBA y la directiva {$interfaces corba}, en todo el c\u00f3digo moderno que trata con interfaces.<\/p>\n\n\n\n<p>Solo si necesita \u00abrecuento de referencias\u00bb y \u00abherencia m\u00faltiple\u00bb al mismo tiempo, utilice las interfaces COM. Adem\u00e1s, Delphi solo tiene interfaces COM por ahora, por lo que debe usar interfaces COM si su c\u00f3digo debe ser compatible con Delphi.<\/p>\n\n\n\n<p><strong>\u00bfPodemos tener un conteo de referencias con interfaces CORBA?<\/strong><\/p>\n\n\n\n<p>S\u00ed. Simplemente agregue los m\u00e9todos _AddRef \/ _ReleaseRef. No es necesario descender de la interfaz IUnknown. Aunque en la mayor\u00eda de los casos, si desea contar referencias con sus interfaces, tambi\u00e9n puede usar interfaces COM.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">GUID de interfaces<\/h3>\n\n\n\n<p>Los GUID son los caracteres aparentemente aleatorios [&#8216;{ABCD1234-\u2026\u200b}&#8217;] que ve colocados en cada definici\u00f3n de interfaz. S\u00ed, son solo al azar. Desafortunadamente, son necesarios.<\/p>\n\n\n\n<p>Los GUID no tienen sentido si no planea integrarse con tecnolog\u00edas de comunicaci\u00f3n como COM o CORBA. Pero son necesarios, por razones de implementaci\u00f3n. No se deje enga\u00f1ar por el compilador, que desafortunadamente le permite declarar interfaces sin GUID.<\/p>\n\n\n\n<p>Sin los GUID (\u00fanicos), el operador is tratar\u00e1 sus interfaces de la misma manera. En efecto, devolver\u00e1 verdadero si su clase admite cualquiera de sus interfaces. La funci\u00f3n m\u00e1gica Supports(ObjectInstance, IMyInterface) se comporta un poco mejor aqu\u00ed, ya que se niega a compilarse para interfaces sin un GUID. Esto es cierto para las interfaces CORBA y COM, a partir de FPC 3.0.0.<\/p>\n\n\n\n<p>Por lo tanto, para estar seguro, siempre debe declarar un GUID para su interfaz. Puede usar el generador GUID de Lazarus (Ctrl + Shift + G atajo en el editor). O puede utilizar un servicio en l\u00ednea como <a href=\"https:\/\/www.guidgenerator.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/www.guidgenerator.com\/<\/a>.<\/p>\n\n\n\n<p>O puede escribir su propia herramienta para esto, usando las funciones <em><code>CreateGUID<\/code><\/em> y <code><em>GUIDToString<\/em><\/code> en RTL. Vea el ejemplo a continuaci\u00f3n:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\nuses\n  SysUtils;\nvar\n  MyGuid: TGUID;\nbegin\n  Randomize;\n  CreateGUID(MyGuid);\n  WriteLn('[''' + GUIDToString(MyGuid) + ''']');\nend.<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Interfaces de conteo de referencia (COM)<\/strong><\/h3>\n\n\n\n<p>Las interfaces COM traen dos caracter\u00edsticas adicionales:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>integraci\u00f3n con COM (una tecnolog\u00eda de Windows, tambi\u00e9n disponible en Unix a trav\u00e9s de XPCOM, utilizada por Mozilla).<\/li>\n\n\n\n<li>conteo de referencias (lo que le brinda destrucci\u00f3n autom\u00e1tica cuando todas las referencias de la interfaz quedan fuera del alcance).<\/li>\n<\/ul>\n\n\n\n<p>Cuando utilice interfaces COM, debe conocer su mecanismo de destrucci\u00f3n autom\u00e1tica y su relaci\u00f3n con la tecnolog\u00eda COM.<\/p>\n\n\n\n<p>En la pr\u00e1ctica, esto significa que:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Su clase necesita implementar m\u00e9todos m\u00e1gicos _AddRef, _Release y QueryInterface. O descender de algo que ya los implementa. Una implementaci\u00f3n particular de estos m\u00e9todos en realidad puede habilitar o deshabilitar la funci\u00f3n de conteo de referencias de las interfaces COM (aunque deshabilitarla es algo peligroso\u2009\u2014\u2009vea el siguiente punto).\n<ul class=\"wp-block-list\">\n<li>La clase est\u00e1ndar TInterfacedObject implementa estos m\u00e9todos para habilitar el conteo de referencias.<\/li>\n\n\n\n<li>La clase est\u00e1ndar TComponent implementa estos m\u00e9todos para deshabilitar el conteo de referencias.  <\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Debe tener cuidado de liberar la clase, cuando algunas variables de interfaz pueden hacer referencia a ella. Debido a que la interfaz se libera utilizando un m\u00e9todo virtual (porque puede contarse por referencia, incluso si piratea el m\u00e9todo _AddRef para que no se cuente por referencia&#8230;), no puede liberar la instancia del objeto subyacente siempre que alguna variable de interfaz pueda apuntar lo. Consulte \u00ab7.7 Recuento de referencias\u00bb en el manual de FPC (<a rel=\"noreferrer noopener\" href=\"http:\/\/freepascal.org\/docs-html\/ref\/refse47.html\" target=\"_blank\">http:\/\/freepascal.org\/docs-html\/ref\/refse47.html<\/a>).<\/li>\n<\/ul>\n\n\n\n<p>El enfoque m\u00e1s seguro para usar las interfaces COM es:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>aceptar el hecho de que son contados por referencia,<\/li>\n\n\n\n<li>derivar las clases apropiadas de TInterfacedObject,<\/li>\n\n\n\n<li> y evite usar la instancia de clase, en lugar de acceder a la instancia siempre a trav\u00e9s de la interfaz, permitiendo que el conteo de referencias administre la desasignaci\u00f3n.<\/li>\n<\/ul>\n\n\n\n<p>Este es un ejemplo de uso de interfaz:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\n{$interfaces com}\n\nuses\n  SysUtils, Classes;\n\ntype\n  IMyInterface = interface\n  ['{3075FFCD-8EFB-4E98-B157-261448B8D92E}']\n    procedure Shoot;\n  end;\n\n  TMyClass1 = class(TInterfacedObject, IMyInterface)\n    procedure Shoot;\n  end;\n\n  TMyClass2 = class(TInterfacedObject, IMyInterface)\n    procedure Shoot;\n  end;\n\n  TMyClass3 = class(TInterfacedObject)\n    procedure Shoot;\n  end;\n\nprocedure TMyClass1.Shoot;\nbegin\n  WriteLn('TMyClass1.Shoot');\nend;\n\nprocedure TMyClass2.Shoot;\nbegin\n  WriteLn('TMyClass2.Shoot');\nend;\n\nprocedure TMyClass3.Shoot;\nbegin\n  WriteLn('TMyClass3.Shoot');\nend;\n\nprocedure UseThroughInterface(I: IMyInterface);\nbegin\n  Write('Disparando... ');\n  I.Shoot;\nend;\n\nvar\n  C1: IMyInterface;  \/\/ COM se preocupa de su destrucci\u00f3n.\n  C2: IMyInterface;  \/\/ COM se preocupa de su destrucci\u00f3n\n  C3: TMyClass3;     \/\/ Debes preocuparte de su destrucci\u00f3n\nbegin\n  C1 := TMyClass1.Create as IMyInterface;\n  C2 := TMyClass2.Create as IMyInterface;\n  C3 := TMyClass3.Create;\n  try\n    UseThroughInterface(C1); \/\/ No es necesario usar el operador 'as'\n    UseThroughInterface(C2);\n    if C3 is IMyInterface then\n      UseThroughInterface(C3 as IMyInterface); \/\/ Esto no se ejecutar\u00e1\n  finally\n    { Las variables C1  C2 fuera del \u00e1mbito ser\u00e1n destruidos en este momento\n      al contrario, C3 es una instancia de una clase, no gestionada \n      por una interface, y tiene que ser destruida manualmente.}\n    FreeAndNil(C3);\n  end;\nend.<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Uso de interfaces COM con el recuento de referencias deshabilitado<\/h3>\n\n\n\n<p>Como se mencion\u00f3 en la secci\u00f3n anterior, su clase puede descender de TComponent (o una clase similar como TNonRefCountedInterfacedObject y TNonRefCountedInterfacedPersistent) que deshabilita el conteo de referencias para las interfaces COM. Esto le permite usar interfaces COM y a\u00fan liberar la instancia de clase manualmente.<\/p>\n\n\n\n<p>En este caso, debe tener cuidado de no liberar la instancia de clase cuando alguna variable de interfaz pueda hacer referencia a ella. Recuerde que cada Cx encasillado como IMyInterface tambi\u00e9n crea una variable de interfaz temporal, que puede estar presente incluso hasta el final del procedimiento actual. Por esta raz\u00f3n, el siguiente ejemplo usa un procedimiento UseInterfaces y libera las instancias de clase fuera de este procedimiento (cuando podemos estar seguros de que las variables de interfaz temporales est\u00e1n fuera del alcance).<\/p>\n\n\n\n<p>Para evitar este l\u00edo, por lo general es mejor usar interfaces CORBA, si no desea contar referencias con sus interfaces.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\n{$interfaces com}\n\nuses\n  SysUtils, Classes;\n\ntype\n  IMyInterface = interface\n  ['{3075FFCD-8EFB-4E98-B157-261448B8D92E}']\n    procedure Shoot;\n  end;\n\n  TMyClass1 = class(TComponent, IMyInterface)\n    procedure Shoot;\n  end;\n\n  TMyClass2 = class(TComponent, IMyInterface)\n    procedure Shoot;\n  end;\n\n  TMyClass3 = class(TComponent)\n    procedure Shoot;\n  end;\n\nprocedure TMyClass1.Shoot;\nbegin\n  WriteLn('TMyClass1.Shoot');\nend;\n\nprocedure TMyClass2.Shoot;\nbegin\n  WriteLn('TMyClass2.Shoot');\nend;\n\nprocedure TMyClass3.Shoot;\nbegin\n  WriteLn('TMyClass3.Shoot');\nend;\n\nprocedure UseThroughInterface(I: IMyInterface);\nbegin\n  Write('Shooting... ');\n  I.Shoot;\nend;\n\nvar\n  C1: TMyClass1;\n  C2: TMyClass2;\n  C3: TMyClass3;\n\nprocedure UseInterfaces;\nbegin\n  if C1 is IMyInterface then\n  \/\/if Supports(C1, IMyInterface) then \/\/ equivalent to \"is\" check above\n    UseThroughInterface(C1 as IMyInterface);\n  if C2 is IMyInterface then\n    UseThroughInterface(C2 as IMyInterface);\n  if C3 is IMyInterface then\n    UseThroughInterface(C3 as IMyInterface);\nend;\n\nbegin\n  C1 := TMyClass1.Create(nil);\n  C2 := TMyClass2.Create(nil);\n  C3 := TMyClass3.Create(nil);\n  try\n    UseInterfaces;\n  finally\n    FreeAndNil(C1);\n    FreeAndNil(C2);\n    FreeAndNil(C3);\n  end;\nend.<\/pre><\/div>\n\n\n\n<h3 class=\"wp-block-heading\">Typecasting interfaces<\/h3>\n\n\n\n<p>Esta secci\u00f3n se aplica a las interfaces CORBA y COM (sin embargo, tiene algunas excepciones expl\u00edcitas para CORBA).<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>La conversi\u00f3n a un tipo de interfaz mediante el operador as realiza una comprobaci\u00f3n en tiempo de ejecuci\u00f3n. Considere este c\u00f3digo:<\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">UseThroughInterface(Cx as IMyInterface);<\/pre><\/div>\n\n\n\n<p>Funciona para todas las instancias C1, C2, C3 en los ejemplos de las secciones anteriores. Si se ejecuta, cometer\u00eda un error en tiempo de ejecuci\u00f3n en el caso de C3, que no implementa IMyInterface.<\/p>\n\n\n\n<p>El uso como operador funciona de forma coherente, independientemente de si Cx se declara como una instancia de clase (como TMyClass2) o una interfaz (como IMyInterface2).<\/p>\n\n\n\n<p>Sin embargo, no est\u00e1 permitido para las interfaces CORBA.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>En su lugar, puede convertir la instancia como una interfaz impl\u00edcitamente:<\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">UseThroughInterface(Cx);<\/pre><\/div>\n\n\n\n<p>En este caso, el typecast debe ser v\u00e1lido en tiempo de compilaci\u00f3n. Entonces esto se compilar\u00e1 para C1 y C2 (que se declaran como clases que implementan IMyInterface). Pero no compilar\u00e1 para C3.<\/p>\n\n\n\n<p>En esencia, este typecast se ve y funciona igual que para las clases normales. Siempre que se requiera una instancia de una clase TMyClass, siempre puede usar all\u00ed una variable que se declara con una clase de TMyClass o descendiente de TMyClass. La misma regla se aplica a las interfaces. No hay necesidad de ning\u00fan typecast expl\u00edcito en tales situaciones.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Tambi\u00e9n puede hacer typecast utilizando IMyInterface(Cx). Como esto:<\/li>\n<\/ul>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">UseThroughInterface(IMyInterface(Cx));<\/pre><\/div>\n\n\n\n<p>Por lo general, dicha sintaxis de typecast indica un typecast y no verificado. Suceder\u00e1n cosas malas si env\u00edas contenido a una interfaz incorrecta. Y eso es cierto, si conviertes una clase a una clase, o una interfaz a una interfaz, usando esta sintaxis.<\/p>\n\n\n\n<p>Aqu\u00ed hay una peque\u00f1a excepci\u00f3n: si Cx se declara como una clase (como TMyClass2), entonces esta es una conversi\u00f3n tipo que debe ser v\u00e1lida en tiempo de compilaci\u00f3n. Por lo tanto, transmitir una clase a una interfaz de esta manera es un typecast y r\u00e1pido (verificado en tiempo de compilaci\u00f3n).<\/p>\n\n\n\n<p>Para probarlo todo, juegue con este c\u00f3digo de ejemplo:<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:delphi decode:true \">{$mode objfpc}{$H+}{$J-}\n\n\/\/ {$interfaces corba} \/\/ note that \"as\" typecasts for CORBA will not compile\n\nuses Classes;\n\ntype\n  IMyInterface = interface\n  ['{7FC754BC-9CA7-4399-B947-D37DD30BA90A}']\n    procedure One;\n  end;\n\n  IMyInterface2 = interface(IMyInterface)\n  ['{A72B7008-3F90-45C1-8F4C-E77C4302AA3E}']\n    procedure Two;\n  end;\n\n  IMyInterface3 = interface(IMyInterface2)\n  ['{924BFB98-B049-4945-AF17-1DB08DB1C0C5}']\n    procedure Three;\n  end;\n\n  TMyClass = class(TComponent, IMyInterface)\n    procedure One;\n  end;\n\n  TMyClass2 = class(TMyClass, IMyInterface, IMyInterface2)\n    procedure One;\n    procedure Two;\n  end;\n\nprocedure TMyClass.One;\nbegin\n  Writeln('TMyClass.One');\nend;\n\nprocedure TMyClass2.One;\nbegin\n  Writeln('TMyClass2.One');\nend;\n\nprocedure TMyClass2.Two;\nbegin\n  Writeln('TMyClass2.Two');\nend;\n\nprocedure UseInterface2(const I: IMyInterface2);\nbegin\n  I.One;\n  I.Two;\nend;\n\nprocedure UseInterface3(const I: IMyInterface3);\nbegin\n  I.One;\n  I.Two;\n  I.Three;\nend;\n\nvar\n  My: IMyInterface;\n  MyClass: TMyClass;\nbegin\n  My := TMyClass2.Create(nil);\n  MyClass := TMyClass2.Create(nil);\n\n  \/\/ This doesn't compile, since at compile-time it's unknown if My is IMyInterface2.\n  \/\/ UseInterface2(My);\n  \/\/ UseInterface2(MyClass);\n\n  \/\/ This compiles and works OK.\n  UseInterface2(IMyInterface2(My));\n  \/\/ This does not compile. Casting InterfaceType(ClassType) is checked at compile-time.\n  \/\/ UseInterface2(IMyInterface2(MyClass));\n\n  \/\/ This compiles and works OK.\n  UseInterface2(My as IMyInterface2);\n  \/\/ This compiles and works OK.\n  UseInterface2(MyClass as IMyInterface2);\n\n  \/\/ This compiles, but will fail at runtime, with ugly \"Access violation\".\n  \/\/ UseInterface3(IMyInterface3(My));\n  \/\/ This does not compile. Casting InterfaceType(ClassType) is checked at compile-time.\n  \/\/ UseInterface3(IMyInterface3(MyClass));\n\n  \/\/ This compiles, but will fail at runtime, with nice \"EInvalidCast: Invalid type cast\".\n  \/\/ UseInterface3(My as IMyInterface3);\n  \/\/ This compiles, but will fail at runtime, with nice \"EInvalidCast: Invalid type cast\".\n  \/\/ UseInterface3(MyClass as IMyInterface3);\n\n  Writeln('Finished');\nend.<\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Sobre este documento<\/h2>\n\n\n\n<p>Copyright Michalis Kamburelis.<\/p>\n\n\n\n<p>El c\u00f3digo fuente de este documento est\u00e1 en AsciiDoc en <a href=\"https:\/\/github.com\/michaliskambi\/modern-pascal-introduction\">https:\/\/github.com\/michaliskambi\/modern-pascal-introduction<\/a>. Las sugerencias de correcciones y adiciones, parches y solicitudes de extracci\u00f3n siempre son bienvenidas \ud83d\ude42 Puede comunicarse conmigo a trav\u00e9s de GitHub o enviar un correo electr\u00f3nico a michalis@castle-engine.io. Mi p\u00e1gina de inicio es<a href=\" https:\/\/michalis.xyz\/\"> https:\/\/michalis.xyz\/<\/a>. Este documento est\u00e1 vinculado en la secci\u00f3n de Documentaci\u00f3n del sitio web de Castle Game Engine <a href=\"https:\/\/castle-engine.io\/\">https:\/\/castle-engine.io\/<\/a>.<\/p>\n\n\n\n<p>Puede redistribuir e incluso modificar este documento libremente, bajo las mismas licencias que Wikipedia <a href=\"https:\/\/en.wikipedia.org\/wiki\/Wikipedia:Copyrights\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/en.wikipedia.org\/wiki\/Wikipedia:Copyrights<\/a>:<\/p>\n\n\n\n<figure class=\"wp-block-pullquote\"><blockquote><p> Licencia Creative Commons Reconocimiento-CompartirIgual 3.0 Unported (CC BY-SA)  o la Licencia de Documentaci\u00f3n Libre GNU (GFDL) (sin versiones, sin secciones invariables, textos de portada o textos de contraportada) .<\/p><\/blockquote><\/figure>\n\n\n\n<p>\u00a1Gracias por leerlo!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Mucha gente considera el lenguaje Pascal, como un lenguaje obsoleto, ya que en internet hay muchos recurso que hablan sobre el lenguaje Pascal, pero hablan sobre el \u00abviejo\u00bb Pascal. Michalis Kamburelis, creador del motor gr\u00e1fico Castle Engine, escribi\u00f3 una gu\u00eda muy concisa y sencilla en la que muestra las caracter\u00edsticas de este lenguaje. El texto [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-473","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/pages\/473","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=473"}],"version-history":[{"count":97,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/pages\/473\/revisions"}],"predecessor-version":[{"id":1052,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/pages\/473\/revisions\/1052"}],"wp:attachment":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=473"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}