Op Mon, 22 Jan 2007, schreef Felipe Monteiro de Carvalho:
> Maybe the compiler could hide the
> procedurization/re-object-orientation, thus making interfacing easier.

Already looked at many times, but it is not realistic.

Can you point me to previous discussion of this? Or perhaps a short
explanation of why, would be nice =)

I did a quick search on fpc mailling lists, found lot´s of talk about
linking to c++ in general, but nothing on the specific topic of hiding
the procedurization/re-object-orientation

thanks,

For a realistic example, download the Kylix patch for QT3 (http://sourceforge.net/project/showfiles.php?group_id=106820) and look at QtLibrary.pas and QtWrappers.pas

It looks something like this:

/* On the C++ side */


class CMyClass{
.....
  public:
    CMyClass(){/* def constructor */};
    ~CMyClass(){/* def destructor */};
    virtual int DoSomething(){ return 42; };
}

/* THE FOLLOWING FUNCTIONS ARE ALL EXPORTED. */
/* The export modifier is different from compiler to compiler, so I skip here */

CMyClass *MyClassFactory(){
  return new CMyClass();
}

DestroyMyClass(CMyClass *instance){
  delete instance();
}

int CMyClass_DoSomething(CMyClass *instance){
  return instance->DoSomething();
}

{ ON THE PASCAL SIDE }

TMyClassImport = class
  protected
    // Override NewInstance and throw a readable exception,
    // explaining that you cannot allocate an imported class.
    // This will happen if you call the Create constructor.
    class function NewInstance: TObject; override;
  public
    // Instead of Create, use the next function as a constructor.
    class function New: TMyClass;
    // This will be used as a destructor
    procedure Delete; cdecl;

    function DoSomething(): Integer; cdecl;

    // Override Free and redirect it to use the Delete function
    // instead of the default Destroy constructor.
    procedure Free; override;
end;

class function TMyClassImport.NewInstance: TObject;
begin
raise Exception.Create('Please, create an instance by using TMyClassImport.New');
end;

function MyClassFactory: TMyClassImport; external DLL_NAME 'MyClassFactory';
class function TMyClassImport.New: TMyClassImport;
begin
  Result := MyClassFactory;
end;

TMyClassImport.Delete; cdecl; external DLL_NAME 'DestroyMyClass';

// Override Free and redirect it to use the Delete function
// instead of the default Destroy destructor
TMyClassImport.Free;
begin
  if Self <> nil then Delete;
end;

TMyClassImport.DoSomething; cdecl; external DLL_NAME 'CMyClass_DoSomething';

At this point you have all the functionality of CMyClass.
Finally, you can define

TMyClass = class
  private
    handle: TMyClassImport;
  public
    function DoSomething: Integer; virtual;
 .......
end;

and here you can redirect all functions to the handle object (TMyClassImport). You can have a normal Create constructor and Destroy destructor, etc. Also, you can do some basic extension of the functionality. In this example,

function TMyClass.DoSomething;
begin
  Result := handle.DoSomething;
end;

Conceivably, you can do some limited extension of DoSomething. TMyClass and all derived classes will allocate a handle of type TMyClassImport so, internally they redirect the calls to the basic methods of CMyClass. So, the C++ side always gets the handle object which has the correct class layout (because it was allocated on the C++ side).

However, suppose that a non-virtual function of CMyClass, say DoSomethingElse, relies on the answer of DoSomething. Any change you make in DoSomething, by dering classes from TMyClass and overriding it will not result in polymorphic behavior of DoSomethingElse. That is, TMyDerivedClass.DoSomethingElse will still forward the handle of the original C++ class (handle.DoSomethingElse) and the later will use the original CMyClass:DoSomething. So the answer will always be 42.

Peter


_______________________________________________
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply via email to