Subject: Re: Object-oriented means for computational chemist

From: Andrew Dalke <[email-masked]>
Date: Thu, 24 Jul 1997 17:30:04 -0500

Hello,

> The issue I was trying to raise is that regardless of whether one
> wants to write the front end in C, C++ or Fortran, or anything else,
> the language definition of C++ *precludes* writing a linkable code 
> libraries in C++ if one ever wants to access the library routines 
> from another language.

  That's not quite true.  The real requirement is you need a linker
that understands how to deal with your C++ compiler .

  For instance, I can write an interface to a C++ class for C by
defining a set of exported functions (in extern "C" context) that
are compiled by C++.  (I put an example at the end of this email.)

  There will be two problems:  The implementations of 'new' and
'delete' require a special function be linked in, which you
will need via the C++ linker.
  There will also be problems if you use C++'s static variables
with class types.  All static variables are initialized at before
main() is run, so the linker has to add the code that runs the
initializations before calling main.  The standard linker doesn't
do this so here again you need to use the C++ linker (this
feature is just not possible with C or Fortran; if variables and
arrays are initialized, they are initialized to 0).

  The biggest limitation is really that I can't link my C++ library
created under one compiler with C++ generated from another.  But
then, all the code I distribute is available in source form so that
hasn't been much of a problem.

						Andrew Dalke
						[email-masked]

Here's an example of C wrapper functions for a C++ class.  There
are three files; the header file includes both the C and C++ APIs.
The file 'class.C' contains the class code and does the C-level
interface, and main.c is a driver.

This uses the 'extern "C"' feature of C++ to turn off name mangling
when compiling under C++.  

= = = = = = = = = class.h = = = = = = =
#ifdef __cplusplus
class MyClass {
  int data;
public:
  MyClass(int new_value);
  ~MyClass(void);
  int get(void);
};

#endif
 /* for the C interface; doing it this way instead of using a void * */
 /* directly lets the compiler do better type checking and keeps the */
 /* same "feel" as C++ */
typedef struct MyClass_C {
  void *class_ptr;
} MyClass_C;

#ifdef __cplusplus
extern "C" {
#endif

  MyClass_C MyClass_new(int new_value);
  void MyClass_delete(MyClass_C);
  int MyClass_get(MyClass_C);

#ifdef __cplusplus
};
#endif

= = = = = = = = = =class.C = = = = = = = = = =
#include <stdlib.h>
#include "class.h"

/* a simple int storage class */
MyClass::MyClass(int new_value) { data = new_value; }
MyClass::~MyClass(void) { data = 0; }
int MyClass::get(void) { return data; }

/* Wrappers for the C interface */
MyClass_C MyClass_new(int new_value) {
  MyClass_C tmp;
  tmp.class_ptr = new MyClass(new_value);
  return tmp;
}
void MyClass_delete(MyClass_C ref) {
  delete ((MyClass *) ref.class_ptr);
  ref.class_ptr = NULL;
}
int MyClass_get(MyClass_C ref) {
  return ((MyClass *) ref.class_ptr)->get();
}

= = = = = = = = = =main.c = = = = = =
 /* The driver code -- compile this in C! */
#include <stdio.h>
#include "class.h"
main()
{
 MyClass_C tmp = MyClass_new(5);
 printf("The value is %d.\n", MyClass_get(tmp));
 MyClass_delete(tmp);
}
= = = = = =

   Here's how I ran it (using GNU's C++ compiler, SGI's C compiler,
and GNU's C++ linker to prove nothing fishy was going on):
% g++ -c class.C
% cc -c main.c
% g++ main.o class.o
% ./a.out
The value is 5.

  So it is possible for C routines to call C++ functions and classes.