Magari a livello implementativo le differenze sono minime, qualche if qua e la :-)
A livello logico le differenze però ci sono. L'interfaccia "corba" di fpc è l'interfaccia "normale", nessun free automatico, nessun guid, nessun metodo AddRef da compilare. E' l'escamotage che, java prima (da qui "alla-java") e c# dopo, si sono inventati per supportare l'ereditarietà multipla in oop.
Senza fare guerre di religione, io penso che se uno ha bisogno delle interfacce oop possa allegramente e felicemente utilizzare l'implementazione data da fpc con l'opzione infelicemente chiamata corba perchè con quella puoi scrivere del codice più semplice e leggibile. Poi liberi tutti, ad esempio per mantenere la compatibilità con Delphi, di lavorare con le interfacce ole/com.
Io ricordo che anche taroccando il contatore qualche problema lo avevamo avuto col nostro ipercubo però non ricordo i dettagli.. se trovo il tempo magari faccio una verifica.
Guarda che Delphi supporta la definizione di interfaccia senza GUID :o
E serve la QueryInterface (e quindi le GUID) se si hanno interfacce multiple derivate nella classe istanziata.
Inoltre la GUID lo dichiari, come ho indicato se devi a runtime effettuare delle operazioni "virtuali" come IS, AS, Supports, ... e quindi anche le QueryInterface deve esserci.
E se nei casi indicati la GUID serve e anche la "QueryInterface" non vedo ripeto alcuna differenza.
Quindi non vedo alcuna differenza. E le interfacce "multiple" sono una caratteristica tipica della OOP, e servono proprio a consentire di fatto l'ereditarietà multipla (come ho già accennato, non è proprio così ma ci si avvicina) che non è consentita attraverso le sole Classi. Penso che esista da sempre.
E per implementarle, fino a prova contraria che vorrei capire, deve esserci la GUID e la QueryInterface.
La mia non è una polemica, vorrei solo capire se effettivamente c'è una strada diversa come dite, ma non riesco a comprenderla. Secondo me parliamo della stessa cosa.
Poi non sono andato nei meandri del codice sorgente ne in FPC ne in Delphi per vedere se a livello assembler fanno qualcosa o magicamente il compilatore si inventa il coniglio nel cappello ... ma non mi interessa questo.
Secondo me la cosa interessante è: si può fare quello sotto scritto senza GUID, senza QueryInterface, senza Addref, senza ReleaseRef ?
Sia in Delphi che in Lazarus ? E con cosa obbligatorio ?
Devo modificare qualcosa per avvicinarci a quello che ho scritto ? Devo cambiare nomi di metodi ? Devo aggiungere qualcosa alle procedure ?
Se no parliamo di aria fritta.
Sono le prove che farò a livello base, cercando di non usare funzioni "speciali", di cui però mi aspetto già le risposte.
Esempio scritto così come me lo immagino (lasciamo perdere se è utile o no):
type
IStampaLaser = interface
procedure Stampa;
end;
IStampaInkjet = interface
procedure Stampa;
end;
TProvadiStampa = Class(TObject, IStampaLaser, IStampaInkJet)
public
procedure Stampa;
end;
Implementation
procedure TProvadiStampa.Stampa;
begin
ShowMessage('Sto stampando con che interfaccia ????');
end;
Appena ho testato posto qui i risultati. Serve anche a me per capire se ci sono altre strade (quella pura Pascal come dite), perchè sino ad ora ho usato la strada classica (quella che viene definita COM) e mi farebbe piacere se ci fosse un altro modo ...
Ciao
visto che ci siamo ho cercato di studiare un po' di più la cosa e mi sono chiesto il perché della rimozione di _AddRef e _ReleaseRef
la risposta, dopo molto girovagare l'ho trovata nell'unico posto dove doveva essere: nella documentazione ufficiale :)
https://www.freepascal.org/docs-html/prog/progsu37.html#x44-430001.2.37
in pratica le interfacce COM differiscono dalle CORBA anche per l'attribuzione del parent
nel caso di COM il parent delle interfacce è IUnknown (tramite TInterfacedObject che deve essere nella dichiarazione della classe, che si occupa del reference counting)
nel caso CORBA, il parent non è necessario ma, per mantenere la compatibilità tra il cambio di direttive, è possibile usare comunque TInterfacedObject come parent della classe finale (ma le chiamate ad _AddRef e _ReleaseRef verranno eliminate)
chiaramente ho fatto qualche prova
usando le interfacce CORBA, la dichiarazione "TMyClass1 = class (IInterfacciaCORBA)" è valida
unit Unit1;
{$mode ObjFPC}{$H+}
{$interfaces corba}
interface
uses
Classes, SysUtils;
type
IInterfacciaCORBA = interface
procedure DoThis (value: integer);
end;
{ TMyClass1 }
TMyClass1 = class (IInterfacciaCORBA)
procedure DoThis (value: integer);
end;
implementation
{ TMyClass1 }
procedure TMyClass1.DoThis(value: integer);
begin
end;
end.
usando invece le interfacce COM, sono costretto a dichiarare la classe come "TMyClass2 = class (TInterfacedObject, IInterfacciaCOM) "
eliminando "TInterfacedObject" dalla dichiarazione si otterrà l'errore di compilazione:
unit2.pas(17,15) Error: No matching implementation for interface method "QueryInterface(constref TGuid;out <Formal type>):System.LongInt; CDecl;" found
unit Unit2;
{$mode ObjFPC}{$H+}
interface
uses
Classes, SysUtils;
type
IInterfacciaCOM = interface
procedure DoThis (value: integer);
end;
{ TMyClass2 }
TMyClass2 = class (TInterfacedObject, IInterfacciaCOM)
procedure DoThis (value: integer);
end;
implementation
{ TMyClass2 }
procedure TMyClass2.DoThis(value: integer);
begin
end;
end.
Edit:
ho visto che anche il GUID nelle CORBA è facoltativo
in quel caso spetta al programmatore evitare conflitti nel nominare le interfacce
Edit 2:
ora che è chiarito l'arcano della rimozione dei metodi _AddRef e _ReleaseRef
ha anche più senso l'implementazione delle interfacce come semplice concetto di ereditarietà multipla:
usando CORBA ed evitando TInterfacedObject si usa in modo pulito l'ereditarietà ma si può sempre ricorrere alla compatibilità se necessario
chapeau :)
nomorelogic