{"id":338,"date":"2023-07-10T08:28:00","date_gmt":"2023-07-10T08:28:00","guid":{"rendered":"https:\/\/jorgeturiel.es\/?p=338"},"modified":"2023-03-20T13:55:06","modified_gmt":"2023-03-20T13:55:06","slug":"introduccion-al-lenguaje-pascal-moderno-para-programadores-parte-9","status":"publish","type":"post","link":"https:\/\/jorgeturiel.es\/?p=338","title":{"rendered":"Introducci\u00f3n al lenguaje Pascal moderno para programadores (Parte 9)"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Interfaces<\/h2>\n\n\n\n<p id=\"block-5521090e-ab25-4c7d-8ff9-7b06a21f4a1b\">Continuamos con la introducci\u00f3n al lenguaje Pascal Moderno.<\/p>\n\n\n\n<p id=\"block-5521090e-ab25-4c7d-8ff9-7b06a21f4a1b\">Esta entrada es una traducci\u00f3n al espa\u00f1ol, del texto <a rel=\"noreferrer noopener\" href=\"https:\/\/castle-engine.io\/modern_pascal\" target=\"_blank\">original<\/a> escrito por Michalis Kamburelis.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\"> Interfaces desnudas (CORBA)<\/h2>\n\n\n\n<p>Una interfaz declara una API, como una clase, pero no define la implementaci\u00f3n. Una clase puede implementar muchas interfaces, pero solo puede tener una clase antecesora.<\/p>\n\n\n\n<p>Puede transmitir una clase a cualquier interfaz que admita y luego llamar a los m\u00e9todos a trav\u00e9s de esa interfaz. Esto permite tratar de manera uniforme las clases que no descienden unas de otras, pero que a\u00fan comparten alguna funcionalidad com\u00fan. \u00datil cuando una herencia de clase simple no es suficiente.<\/p>\n\n\n\n<p>Las interfaces CORBA en Object Pascal funcionan de manera muy similar a las interfaces en Java (<a rel=\"noreferrer noopener\" href=\"https:\/\/docs.oracle.com\/javase\/tutorial\/java\/concepts\/interface.html\" target=\"_blank\">https:\/\/docs.oracle.com\/javase\/tutorial\/java\/concepts\/interface.html<\/a>) o C# (<a rel=\"noreferrer noopener\" href=\"https:\/\/msdn.microsoft.com\/en -us\/library\/ms173156.aspx\" target=\"_blank\">https:\/\/msdn.microsoft.com\/en -us\/library\/ms173156.aspx<\/a>).<\/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 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('Shooting... ');\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    \/\/ The \"C3 is IMyInterface\" below is false,\n    \/\/ so \"UseThroughInterface(C3 as IMyInterface)\" will not execute.\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<p><strong>\u00bfPor qu\u00e9 las interfaces (presentadas arriba) se llaman \u00abCORBA\u00bb?<\/strong><\/p>\n\n\n\n<p>El nombre <strong>CORBA <\/strong>es desafortunado. Un mejor nombre ser\u00eda interfaces desnudas (<strong>bare interfaces<\/strong>). Estas interfaces son una \u00abfunci\u00f3n de lenguaje puro\u00bb. \u00daselos cuando desee emitir varias clases como la misma interfaz, ya que comparten una API com\u00fan. Si bien estos tipos de interfaces se pueden usar junto con la tecnolog\u00eda CORBA (Common Object Request Broker Architecture) (<a rel=\"noreferrer noopener\" href=\"https:\/\/en.wikipedia.org\/wiki\/Common_Object_Request_Broker_Architecture\" target=\"_blank\">ver wikipedia sobre CORBA<\/a>), no est\u00e1n vinculados a esta tecnolog\u00eda de ninguna manera.<\/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 {$interfaces xxx} solo afecta a las interfaces que no tienen ning\u00fan ancestro expl\u00edcito (solo la palabra clave interface, no interface(ISomeAncestor)). Cuando una interfaz tiene un ancestro, tiene el mismo tipo que el ancestro, independientemente de la declaraci\u00f3n {$interfaces xxx}.<\/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 IUnknown. Descendente de IUnknown:<\/p>\n\n\n\n<p>Requiere que sus clases definan los m\u00e9todos _AddRef y _ReleaseRef. 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 QueryInterface. <\/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<h2 class=\"wp-block-heading\">GUID de interfaces<\/h2>\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 CreateGUID y GUIDToString 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<h2 class=\"wp-block-heading\"><strong>Interfaces de conteo de referencia (COM)<\/strong><\/h2>\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('Shooting... ');\n  I.Shoot;\nend;\n\nvar\n  C1: IMyInterface;  \/\/ COM takes care of destruction\n  C2: IMyInterface;  \/\/ COM takes care of destruction\n  C3: TMyClass3;     \/\/ YOU have to take care of destruction\nbegin\n  C1 := TMyClass1.Create as IMyInterface;\n  C2 := TMyClass2.Create as IMyInterface;\n  C3 := TMyClass3.Create;\n  try\n    UseThroughInterface(C1); \/\/ no need to use \"as\" operator\n    UseThroughInterface(C2);\n    if C3 is IMyInterface then\n      UseThroughInterface(C3 as IMyInterface); \/\/ this will not execute\n  finally\n    { C1 and C2 variables go out of scope and will be auto-destroyed now.\n\n      In contrast, C3 is a class instance, not managed by an interface,\n      and it has to be destroyed manually. }\n    FreeAndNil(C3);\n  end;\nend.<\/pre><\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Uso de interfaces COM con el recuento de referencias deshabilitado<\/h2>\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<h2 class=\"wp-block-heading\">Typecasting interfaces<\/h2>\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>Interfaces Continuamos con la introducci\u00f3n al lenguaje Pascal Moderno. Esta entrada es una traducci\u00f3n al espa\u00f1ol, del texto original escrito por Michalis Kamburelis.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[27,25,26],"tags":[22,23,21,24],"class_list":["post-338","post","type-post","status-publish","format-standard","hentry","category-lazarus","category-pascal","category-programacion","tag-delphi","tag-lazarus","tag-pascal","tag-programacion"],"_links":{"self":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts\/338","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/types\/post"}],"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=338"}],"version-history":[{"count":5,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts\/338\/revisions"}],"predecessor-version":[{"id":559,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=\/wp\/v2\/posts\/338\/revisions\/559"}],"wp:attachment":[{"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=338"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=338"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jorgeturiel.es\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=338"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}