Home | Contact | Pricing | News | Events | Partners | Mailing List | Site Map
Gnat Pro. Powerful tools. Frontline Support. Ada expertise.

Gem #61: Interfacing with C++ constructors

Author: Javier Miranda, Arnaud Charlet, AdaCore

Abstract: Ada Gem #61 — In the previous Gem about generating bindings from C++ headers, we mentioned, without going into details, how to interface with C++ constructors in Ada using the CPP_Constructor pragma.

In this Gem we present some common uses of C++ constructors in mixed-language programs in GNAT, and in the next Gem, we will show the use of some powerful Ada 2005 features in conjunction with C++ constructors.

« Previous Gem | Next Gem » | Gems Menu

Let’s get started…


Let’s assume that we need to interface with the following C++ class:

class Root {
public:
   int  a_value;
   int  b_value;
   virtual int Get_Value ();
   Root();              // Default constructor
   Root(int v);         // 1st non-default constructor
   Root(int v, int w);  // 2nd non-default constructor
};

Using the automatic binding generator, or writing manually, we can obtain the corresponding package spec:

with Interfaces.C; use Interfaces.C;
package Pkg_Root is

   type Root is tagged limited record
       A_Value : int;
       B_Value : int;
   end record;
   pragma Import (CPP, Root);

   function Get_Value (Obj : Root) return int;
   pragma Import (CPP, Get_Value);

   function New_Root return Root'Class;
   pragma Cpp_Constructor (New_Root, "_ZN4RootC1Ev");

   function New_Root (v : int) return Root'Class;
   pragma Cpp_Constructor (New_Root, "_ZN4RootC1Ei");

   function New_Root (v, w : int) return Root'Class;
   pragma Cpp_Constructor (New_Root, "_ZN4RootC1Eii");

end Pkg_Root;

On the Ada side, the constructor is represented by a function (whose name is arbitrary) that returns the class-wide type corresponding to the imported C++ class. The return type is required to be class-wide rather than the specific Root type so that the function will not be treated as a primitive dispatching operation of the type. Although the constructor is described as a function, it is typically a procedure with an extra implicit argument (the object being initialized) at the implementation level. GNAT issues the appropriate call, whatever it is, to initialize the object.

Constructors can appear in the following contexts:

- As the initialization expression of an object of type T
- As the initialization expression of a record component of type T
- In a limited aggregate
- In a limited aggregate used as the expression of a return statement

Note that all of the above contexts are places where Ada 2005 allows limited aggregates and calls to functions with limited results to appear, and in fact it’s necessary to enable the Ada 2005 compilation mode (-gnat05) to make use of this feature.

In a declaration of an object whose type is a class imported from C++, either the default C++ constructor is implicitly called by GNAT, or else the required C++ constructor must be explicitly called in the expression that initializes the object. For example:

 Obj1 : Root;
 Obj2 : Root := New_Root;
 Obj3 : Root := New_Root (v => 10);
 Obj4 : Root := New_Root (30, 40);

The first two declarations are equivalent: in both cases, the default C++ constructor is invoked (in the former case the call to the constructor is implicit, and in the latter case the call is explicit in the object declaration). Obj3 is initialized by the C++ nondefault constructor that takes an integer argument, and Obj4 is initialized by the nondefault C++ constructor that takes two integers.

It’s worth pointing out that normally it’s not permitted to call a class-wide function to initialize an object of a specific type, and it’s only in the case of these special imported constructor functions that the compiler allows this usage.

In the next Gem we will explore how to derive and extend imported C++ classes on the Ada side, and show uses of constructors in Ada 2005 extended return and limited aggregates.

 

Posted by Posted in Ada / Ada 2005 / Ada 2012, Development Log, Devt log - Gem of the Week

Have your own idea for a Gem?

If you have an idea for a Gem you would like to contribute please feel free to contact us at: gems@adacore.com

Discussion

6 responses to “Gem #61: Interfacing with C++ constructors”


  1. Anh Vo said:

    Thanks for these GEMs dealing with external languages such specially C/C++.

    The following comment has nothing to do with content but with the display regarding apostropy “‘”. In fact, apostropy is not displayed correctly as intended such as in function specification function New_Root return Root'Class; for example. Instead, the ' string is display. According to http://www.w3.org/TR/xhtml1/#C_16, &#39 should be used instead of '


  2. Anh Vo said:

    Sorry I made a typo in “Instead, the ' string is display”. It should be displayed.


  3. Arnaud Charlet said:

    Thanks for the comment. Strangely enough, the ‘ appears fine on e.g. my side. I guess it depends on your browser.

    Anyway, I’ve made your suggested change (apos -> amp).


  4. Anh Vo said:

    I am using Micro$oft Internet Explorer Version 6.0. The exact version is 6.0.2900.2180.xpsp_sp2_qfe.080814-1242.

    Your fix did not seem to change the display. In fact, ' is displayed still. As a test, I copied the source of this page. Then, I replaced every occurrence of ' by &#39. Finally, I opened it with explorer. The apostropy was displayed correctly as expected.


  5. Anh Vo said:

    I just tested it on FireFox. The apostropy was displayed correctly.


  6. Dave Elliot said:

    It looks apos is an XML form (not in the HTML 4 standard). The character code 39 has to be used for Internet Explorer. It appears here that IE is following the standard closer.

Leave a Reply