Using a C++ Class in Ada95 / Constructors and Controlled Types
I would like to be able to use a C++ class in my Ada code. My goal is to keep my Ada code portable to the Ada95 specification. I don't want to use any of the GNAT or Ada05 specific methodologies.
I am using pragma Import (C) with wrapper functions in C to achieve my interfaces. But I am having trouble figuring out how to get my C++ Ctors/Dtors to get called automatically. My first thought was to use Ada Controlled Types and the Initialize would call the Ctor and Finalize would call the Dtor. This was all fine and good until I had a Ctor that needed me to pass parameters.
Foo.h
class Foo
{
public:
Foo();
Foo(long x, long y, long z);
Foo(const Foo& that);
~Foo();
Foo& operator=(const Foo& that);
long getX() const;
long getY() const;
long getZ() const;
void setX(long x);
void setY(long y);
void setZ(long z);
private:
long mX;
long mY;
long mZ;
};
Foo_Exports.cpp
#include "foo.h"
#include <new>
extern "C"
{
void extFoo_New (Foo* foo) { new (foo) Foo(); }
void extFoo_NewXYZ (Foo* foo, long x, long y, long z) { new (foo) Foo(x,y,z); }
void extFoo_Delete (Foo* foo) { foo->~Foo(); }
long extFoo_getX(const Foo& foo) { return foo.getX(); }
long extFoo_getY(const Foo& foo) { return foo.getY(); }
long extFoo_getZ(const Foo& foo) { return foo.getZ(); }
void extFoo_setX(const Foo& foo, long x) { foo.setX(x) };
void extFoo_setY(const Foo& foo, long y) { foo.setY(y) };
void extFoo_setZ(const Foo& foo, long z) { foo.setZ(z) };
}
cpp.foo.ads
with Ada.Finalization;
with Interfaces.C;
use Interfaces.C;
package Cpp.Foo is
type Obj_t is new Ada.Finalization.Controlled_Type with private;
procedure Initialize (This : in out Obj_T);
procedure Adjust (This : in out Obj_T);
procedure Finalize (This : in out Obj_T);
function Get_X (This : access Obj_T) return Long;
function Get_Y (This : access Obj_T) return Long;
function Get_Z (This : access Obj_T) return Long;
procedure Set_X(This : access Obj_T;
X : in Long );
procedure Set_Y(This : access Obj_T;
Y : in Long );
procedure Set_Z(This : access Obj_T;
Z : in Long );
private
type Obj_t is new Ada.Finalization.Controlled_Type with null record;
for Obj_T'Size use 192;
for Obj_T'Alignment use 8;
pragma Import (C, Get_X, "extFoo_getX");
pragma Import (C, Get_Y, "extFoo_getY");
pragma Import (C, Get_Z, "extFoo_getZ");
pragma Import (C, Set_X, "extFoo_setX");
pragma Import (C, Set_Y, "extFoo_setY");
pragma Import (C, Set_Z, "extFoo_setZ");
end Cpp.Foo;
cpp.foo.adb
with System;
package body Cpp.Foo is
procedure Initialize (This : in out Obj_T) is
procedure ExtFoo_New(Addr : in System.Address);
pragma Import (C, ExtFoo_New "extFoo_New");
procedure ExtFoo_NewXYZ(Addr : in System.Address,
X : in Long;
Y : in Long;
Z : in Long);
pragma Import (C, ExtFoo_NewXYZ "extFoo_NewXYZ");
begin
null; -- **WHAT DO I DO HERE?!**
end Initialize;
procedure Adjust (This : in out Obj_T) is
begin
null; -- TBD copy ctor
end Adjust;
procedure Finalize (This : in out Obj_T) is
procedure ExtFoo_Delete(Addr : in System.Address);
pragma Import (C, ExtFoo_Delete, extFoo_Delete);
begin
ExtFoo_Delete(This'address);
end Finalize;
end Cpp.Foo;
Initialize will only be called for default initialization:
O : Obj_t;
and is the subprogram that should call ExtFoo_New. In order to create an Obj_t with initial values, you need another function to call ExtFoo_NewXYZ, perhaps
function Create (X, Y, Z : Long_Integer) return Obj_T;
and then
O : Obj_T := Create (41, 42, 43);
That said, I really don’t think your scheme of overlaying the Ada Obj_t and the C++ Foo is a good idea, because both languages are entitled to use hidden fields. I can imagine that C++ might store a pointer to a dispatch table, and I know for certain that (in GNAT) a child of Ada.Finalization.Controlled contains links that implement a finalization chain. Other compilers may well do it a different way (and GNAT changed its strategy in GCC 4.7). So I would have Obj_t contain a reference to the C++ object (that is, the value returned by Foo()).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With