Access Fortran Class from C++

Access Fortran Class from C++

Dear all,

I like to use from C++ a class which is coded in Fotran inside a modul. I haved tried to pass the pointer from Fortran to C++ and back again later. But this seems not to work, if calling virtual functions.

Here is the code of the base and the dreived class: module.f

      MODULE BASE_TYPE
      TYPE :: base
      real(8) :: num
      CONTAINS
      final     :: base_dtor
      procedure :: speak => base_speak
      procedure :: init
      END TYPE BASE
!
      CONTAINS
      subroutine base_dtor(this)
      TYPE(base), intent(inout) :: this
      print *, "base_dtor"
      end subroutine
!
      subroutine base_speak(this)
      CLASS(base), intent(in) :: this
      print *, "speak: base ", this%num
      end subroutine
!
      subroutine init(this, n)
      CLASS(base), intent(inout) :: this
      real(8), intent(in)     :: n
      this%num = n
      end subroutine
!
      END MODULE BASE_TYPE
!
!
      MODULE DERIVED_TYPE
      USE BASE_TYPE
      TYPE, EXTENDS(BASE) :: DERIVED
      CONTAINS
      final     :: derived_dtor
      procedure :: speak => derived_speak
      END TYPE DERIVED
!
      CONTAINS
      subroutine derived_dtor(this)
      TYPE(derived), intent(inout) :: this
      print *, "derived_dtor"
      end subroutine
!
      subroutine derived_speak(this)
      CLASS(derived), intent(in) :: this
      print *, "speak: derived ", this%num
      end subroutine
!
      END MODULE DERIVED_TYPE

The interface for C++: interface.f

      subroutine base_get( cptr )
      use iso_c_binding
      use base_type
      use derived_type
      type(c_ptr), intent(out)   :: cptr
      type(base), pointer :: fptr
      allocate(fptr)
      cptr=c_loc(fptr)
      end subroutine
!
      subroutine base_free( cptr )
      use iso_c_binding
      use base_type
      use derived_type
      type(c_ptr), intent(in)   :: cptr
      type(base), pointer :: fptr
      call c_f_pointer( cptr, fptr)
      deallocate(fptr)
      end subroutine
!
      subroutine base_init( cptr, num )
      use iso_c_binding
      use base_type
      use derived_type
      type(c_ptr), intent(in)   :: cptr
      real(8),    intent(in)   :: num
      type(base), pointer :: fptr
      call c_f_pointer( cptr, fptr)
      call fptr%init(num)
      end subroutine
!
      subroutine base_speak( cptr )
      use iso_c_binding
      use base_type
      use derived_type
      type(c_ptr), intent(in)   :: cptr
      type(base), pointer :: fptr
      call c_f_pointer( cptr, fptr)
      call fptr%speak
      end subroutine
!
!
      subroutine derived_get( cptr )
      use iso_c_binding
      use base_type
      use derived_type
      type(c_ptr), intent(out)   :: cptr
      type(derived), pointer :: fptr
      allocate(fptr)
      cptr=c_loc(fptr)
      end subroutine
!
      subroutine derived_free( cptr )
      use iso_c_binding
      use base_type
      use derived_type
      type(c_ptr), intent(in)   :: cptr
      type(derived), pointer :: fptr
      call c_f_pointer( cptr, fptr)
      deallocate(fptr)
      end subroutine
!
      subroutine derived_init( cptr, num )
      use iso_c_binding
      use base_type
      use derived_type
      type(c_ptr), intent(in)   :: cptr
      real(8),    intent(in)   :: num
      type(derived), pointer :: fptr
      call c_f_pointer( cptr, fptr)
      call fptr%init(num)
      end subroutine
!
      subroutine derived_speak( cptr )
      use iso_c_binding
      use base_type
      use derived_type
      type(c_ptr), intent(in)   :: cptr
      type(derived), pointer :: fptr
      call c_f_pointer( cptr, fptr)
      call fptr%speak
      end subroutine

The C++ test: test_interface.cpp

#include <cstdio>
// function for base
extern "C" void base_get_(void **ptr);
extern "C" void base_free_(void **ptr);
extern "C" void base_init_(void **ptr, const double *);
extern "C" void base_speak_(void **ptr);
// function for derived
extern "C" void derived_get_(void **ptr);
extern "C" void derived_free_(void **ptr);
extern "C" void derived_init_(void **ptr, const double *);
extern "C" void derived_speak_(void **ptr);
// test function
extern "C" void test_interface_(void)
{
  void *ptr;
  double num;
// the following lines seems to work (the output is correct)
  num=10.0;
  printf("\nbase -> base %e\n", num);
  base_get_(&ptr);
  base_init_(&ptr, &num);
  base_speak_(&ptr);
  base_free_(&ptr);
// the following lines seems also to work (the output is correct)
  num=20.0;
  printf("\nderived -> derived %e\n", num);
  derived_get_(&ptr);
  derived_init_(&ptr, &num);
  derived_speak_(&ptr);
  derived_free_(&ptr);
//
  num=30.0;
  printf("\nderived -> base %e\n", num);
  derived_get_(&ptr);
  base_init_(&ptr, &num); // num is set correctly
  base_speak_(&ptr); // the base function is called
  base_free_(&ptr); // only the destructor of base is called
}

One problem might be, that I probably need to declare the pointer as CLASS(BASE), pointer ::fptr to deal with virtual functions correctly, but then I cannot convert the c_ptr pointer using the call c_f_pointer( cptr, fptr) subroutine.

Do you have any ideas/workarounds or is there an official way to acces a Fotran class from C++?

Thank you,

Martin

2 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

There are lots of experts on Intel Fortran Forum who will be answer all your questions and help. By the way, that subject is regularly discussed on Intel Fortran Forum.

Leave a Comment

Please sign in to add a comment. Not a member? Join today