Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a C++ Class in Ada95 / Constructors and Controlled Types

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;
like image 938
Jerunh Avatar asked Dec 05 '25 10:12

Jerunh


1 Answers

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()).

like image 187
Simon Wright Avatar answered Dec 07 '25 23:12

Simon Wright



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!