Extern C++

General FreeBASIC programming questions.
Post Reply
Cretin Ho
Posts: 182
Joined: Feb 04, 2021 13:01

Extern C++

Post by Cretin Ho »

I have read a piece of code on this forum when the OP uses C++ directly from FB without wrappers but unfortunately the forum search can't find this thread. I wanted to know more about this "Extern C++" stuffs. e.g: How to translate C++ constructor? How to deal with C++ multiple inheritance.
Cretin Ho
Posts: 182
Joined: Feb 04, 2021 13:01

Re: Extern C++

Post by Cretin Ho »

Cretin Ho wrote:I have read a piece of code on this forum when the OP uses C++ directly from FB without wrappers but unfortunately the forum search can't find this thread. I wanted to know more about this "Extern C++" stuffs. e.g: How to translate C++ constructor? How to deal with C++ multiple inheritance.
No one knows about this "Extern C++" stuff?

p/s: Finally find the thread: viewtopic.php?f=7&t=28527
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Extern C++

Post by jj2007 »

Cretin Ho wrote:unfortunately the forum search can't find this thread
Google: About 82 results for site:freebasic.net "extern c++"
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Extern C++

Post by dodicat »

Here are some experiments with this stuff.
viewtopic.php?f=3&t=28338&p=272557&hili ... 2A#p272557
Read through both pages.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Extern C++

Post by dodicat »

Here is an example using a C++ template:

quicksort.cpp

Code: Select all


#include<vector>
#include<iostream>
using namespace std;
enum {up,down};


template <typename T>
 void quicksort(T &array,int begin,int finish,int direction)
 {
 int i=begin,j=finish;
 auto& X =array[ (int)((i+j))/2] ;  
 while (i <= j)
 {	
 if(direction==up)
 {while (array[i]  < X ) i++;
 while (array[j]  > X ) j--;}
 if(direction==down)
 {while (array[i]  > X ) i++;
  while (array[j]  < X ) j--;}
 if (i<=j) {swap (array[i],array[j]); i++;j--;};
 };
 if (j >begin)  quicksort(array,begin,j,direction);
 if (i <finish) quicksort(array,i,finish,direction);
}

void sort(vector<int> &v,int s,int e,int direction)
{
	cout<<"Integer sort"<<endl;
quicksort(v,s,e,direction);	
}

void sort(vector<double> &v,int s,int e,int direction)
{
	cout<<"double sort"<<endl;
quicksort(v,s,e,direction);	
}  
usage and instructions at botton:

Code: Select all


#inclib "quicksort"
#inclib "stdc++"

enum direction
      up
      down
end enum

extern "c"
declare sub sort overload  alias "_Z4sortRSt6vectorIdSaIdEEiii"(a() as double,start as integer<32>,fin as integer<32>,direction as integer<32>)
declare sub sort overload  alias "_Z4sortRSt6vectorIiSaIiEEiii"(a() as long,start as integer<32>,fin as integer<32>,direction as integer<32>)
end extern

redim as double b(1 to 10000000)
for n as long=1 to 10000000
      b(n)=rnd*10000000
      next
sort(b(),1,10000000,down)

for n as long=1 to 10
      print b(n)
next
print
dim as long  g(...)={4,6,5,-5,8,10}
sort(g(),0,5,up)
for n as long=0 to 5
      print g(n)
next
sleep

'USING quicksort.cpp:
'for static lib
'g++ -O2 -c quicksort.cpp
'ar rcs -o libquicksort.a quicksort.o
 
 'for dll
'g++ -O2 quicksort.cpp -shared -o quicksortx.dll -Wl,--kill-at,--output-def,quicksortx.def,--out-implib,quicksortx.a
 
Note: I had to use the decorated names.
I used the static file libquicksort.a
If you use a .dll no need to
#inclib "stdc++"
result

Code: Select all

double sort
 9999999.746214598
 9999999.105930328
 9999997.962731868
 9999993.66234988
 9999998.62164259
 9999997.98135832
 9999984.18847099
 9999982.859008014
 9999981.264118105
 9999990.994110704

Integer sort
-5
 4
 5
 6
 8
 10
 
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: Extern C++

Post by caseih »

FB's ability to interact with C++ code is very limited. Dodicat's code is interesting. But the fact that it works at all is down to the coincidence that the in-memory layout of a Vector<> stl class in C++ is the same as an FB array. I'd be very careful about doing that.

Extern C++ simply tells the FB compiler that the symbols you are accessing are mangled according to GCC's c++ mangling specification (see dodicat's example for what the mangling looks like). That's pretty much it.

All FB can deal with are single-inheritance classes from C++. Also there's no support for C++ vtables, so any class hierarchy that uses virtual classes with virtual methods (polymorphism) simply won't work from FB. The only way to have perfect interoperability with C++ classes is to have an object model in FB that is identical to C++. And of course there's no support for C++ template classes.

Further, you won't be able to work with Visual Studio -created C++ dlls. Different compilers mangle names differently and their object models differ slightly too. This has been a problem with C++ for many years that's recently been addressed in the C++ standards finally. For a long time you couldn't mix DLLs from different compilers.

If you need to interact with more advanced C++ code, you'll likely have to write C wrappers and export those to FB. This is how wxWidgets works with FB, for example. That's natively C++, but there is a C wrapper that FB works with.
Cretin Ho
Posts: 182
Joined: Feb 04, 2021 13:01

Re: Extern C++

Post by Cretin Ho »

caseih wrote:If you need to interact with more advanced C++ code, you'll likely have to write C wrappers and export those to FB. This is how wxWidgets works with FB, for example. That's natively C++, but there is a C wrapper that FB works with.
This is what I feared most. The library used sophisticated macros to emulate Qt's MOC. All of the constructors were indeed defined by that macro but not explicitly written. And it make use of very complex multi level of multi inheritance.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Extern C++

Post by dodicat »

If you use C++ vtables for virtual functions + constructors then you are in trouble.
If you don't use the C++ vtables then it would be worth a try maybe.
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: Extern C++

Post by caseih »

No chance of interacting with Qt from FB, unfortunately. Qt does not use multiple inheritance and it does use standard C++ (moc is used to generate some glue classes for event handling, but the underlying C++ code is vanilla standard), but it does use template classes and virtual classes. In theory you could use the same tools that are used to Python and other bindings for Qt to make wrappers for FB, but it wouldn't be trivial or easy at all. There's a lot of complex auxiliary bits to Qt as well, such as casting macros. All of that would have to be implemented in some fashion.

GTK got it right sticking to C. It's trivial to bind to most any language. C++ is powerful, but nothing out there is 100% compatible with its object model.
Cretin Ho
Posts: 182
Joined: Feb 04, 2021 13:01

Re: Extern C++

Post by Cretin Ho »

caseih wrote:No chance of interacting with Qt from FB, unfortunately. Qt does not use multiple inheritance and it does use standard C++ (moc is used to generate some glue classes for event handling, but the underlying C++ code is vanilla standard), but it does use template classes and virtual classes. In theory you could use the same tools that are used to Python and other bindings for Qt to make wrappers for FB, but it wouldn't be trivial or easy at all. There's a lot of complex auxiliary bits to Qt as well, such as casting macros. All of that would have to be implemented in some fashion.

GTK got it right sticking to C. It's trivial to bind to most any language. C++ is powerful, but nothing out there is 100% compatible with its object model.
If it's not Qt but CopperSpice (already got rid of MOC but emulates MOC using macros) or the FOX toolkit (never have MOC but also emulates MOC using macros)? The former is C++ heavy, stick with the latest standard but the later is fine with C++98 (the gnu++98 variant, though). The later also less complex, but the fact is it employs similar macros technique and as a C++ library has made heavy use of operators overloading and multiple inheritance, I think both of them are as hopeless.

A long time in the past I tried to write a wrapper for the FOX library to be able to call from FB. But finally had to give up, because I have no idea to translate multiple inheritances and the object system (macros) employed by FOX to plain C.
Cretin Ho
Posts: 182
Joined: Feb 04, 2021 13:01

Re: Extern C++

Post by Cretin Ho »

The object system is the real culprit. These libraries have their own object system on-top of the C++ object system. These are defined using macros. e.g: FX_DECLARE(Foo), CS_OBJECT(Bar). These are too hard, I have no idea how to translate them to plain C, so I think I will have more luck interfacing with C++ directly from FB.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Extern C++

Post by dodicat »

Test Extern "C++".
classes, inheritance, constructors, methods.
Using only a plus method for brevity.
complex.cpp

Code: Select all

#include<iostream>

using namespace std;

class realnumber
{
	public:
	double real;
	realnumber(double x);
	realnumber();
	realnumber plus(double n);
};

realnumber::realnumber()
{
	cout<<"empty constructor for realnumber"<<endl;
};

realnumber::realnumber(double x)
{
		cout<<"constructor for realnumber(double)"<<endl;
	real=x;
};

realnumber realnumber:: plus(double n)
{
	cout<<"realnumber plus(double)"<<endl;
	return real+n;
}




class complex:public realnumber
{
	public:
	double imaginary;
	complex(const complex &c);
	complex(double x,double y);
	complex();
	complex plus(const complex &c);
	complex addup(double a,double b);
	void show();
};



complex::complex()
{
	cout<<"empty constructor for complex"<<endl;
};

complex::complex(const complex &c)
{
	cout<<"constructor for complex(complex)"<<endl;
	real=c.real;
	imaginary=c.imaginary;
};

complex::complex(double x,double y)
{
		cout<<"constructor for complex(double,double)"<<endl;
	real=x;
	imaginary=y;
};

complex complex::plus(const complex &c)

{
	cout<<"complex plus(complex)"<<endl;
	return complex(real+c.real,imaginary+c.imaginary);	
}

void complex::show()
{
	cout<<"complex show()"<<endl;
	cout<<real<<" , "<<imaginary<<" i"<<endl;
}

complex complex::addup(double a,double b)
{
	cout<<"complex addup(double,double)"<<endl;
return complex(real+a,imaginary+b);
}

class carray:public complex
{
public:
	complex a[21];
	carray();
	void push(int index,const complex &v);
};

carray::carray()
{
	cout<<" constructor for carray"<<endl;
	for (int i=0;i<21;i++)
	{
		a[i].real=0;
		a[i].imaginary=0;
	}
};


void carray::push(int index,const complex &v)
{
	cout<<"carray push"<<endl;
	a[index]=v;
}



 
The .bas test file

Code: Select all




#inclib "complex"
#inclib "stdc++"

extern "C++"
type realnumber
      as double real
      declare constructor
      declare constructor(as double)
      declare function plus(as double) as double
end type

type complex extends realnumber
      as double imaginary
      declare constructor
      declare constructor(c as const complex)
      declare constructor(as double,as double)
      declare function plus(c as const complex) as complex
      declare sub show()
      declare function addup(as double,as double) as complex
end type

type carray extends complex
         as complex a(21)
         declare constructor()
      declare sub push(as long, as const complex)
end type
end extern

dim as realnumber x=9
dim as double y=7
var p= x.plus(y)
print p

print"-----"
dim as complex a,b,c
c=type<complex>(type<complex>(9.9,8.8))
c.show()
b=type(9,7)
a=type(-5,-70)
b.show()
c=b.addup(6,3)
c.show()

a.show()
c=a.plus(b)
c.show()

dim as carray w

dim as complex d=type(5,7)
w.push(0,d)
w.push(1,type<complex>(4,4))
w.push(2,type<complex>(40,40))

for n as long=0 to 2
      w.a(n).show()
next

'for static lib
'g++ -c complex.cpp
'ar rcs -o libcomplex.a complex.o

sleep


 
No problems, so long as you don't need the C++ vtable for virtual methods.
I have used a static .a library to test.
result

Code: Select all

constructor for realnumber(double)
realnumber plus(double)
constructor for realnumber(double)
 16
-----
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
constructor for complex(double,double)
empty constructor for realnumber
constructor for complex(complex)
complex show()
9.9 , 8.8 i
empty constructor for realnumber
constructor for complex(double,double)
empty constructor for realnumber
constructor for complex(double,double)
complex show()
9 , 7 i
complex addup(double,double)
empty constructor for realnumber
constructor for complex(double,double)
complex show()
15 , 10 i
complex show()
-5 , -70 i
complex plus(complex)
empty constructor for realnumber
constructor for complex(double,double)
complex show()
4 , -63 i
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
empty constructor for realnumber
empty constructor for complex
 constructor for carray
empty constructor for realnumber
constructor for complex(double,double)
carray push
empty constructor for realnumber
constructor for complex(double,double)
carray push
empty constructor for realnumber
constructor for complex(double,double)
carray push
complex show()
5 , 7 i
complex show()
4 , 4 i
complex show()
40 , 40 i
 
Cretin Ho
Posts: 182
Joined: Feb 04, 2021 13:01

Re: Extern C++

Post by Cretin Ho »

@dodicat Does vtable means virtual methods?
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Extern C++

Post by dodicat »

Yes, all virtual methods are recorded in a vtable in C++ and fb.
Unfortunately C++ and fb vtables do not match very well.
If you don't use constructors in your fb code (ie don't call any C++ constructors) then they seem to match properly, but I haven't tested this thoroughly.
Post Reply