Próbuję nawiązać współpracę z C++ i D. A to, co znalazłem dzisiaj, naprawdę psuje mój umysł: obiekty nie są poprawnie przekazywane w moim programie.Jak przekazać obiekt z D do C++?
Lepiej pokazać przykład.
Mam bibliotekę C++, którą kompiluję do pliku obiektowego i programu D, który łączę z moją biblioteką i uruchamiam.
Oto one:
#include <stdio.h>
class Color
{
public:
Color(unsigned int _r, unsigned int _g, unsigned int _b) : r(_r), g(_g), b(_b) {}
unsigned int r, g, b;
};
class Printer
{
public:
Printer() {}
~Printer() {}
static Printer* getInstance();
void print(Color *c);
};
Printer* Printer::getInstance()
{
return new Printer();
}
void Printer::print(Color *c)
{
printf("(%d, %d, %d)\n", c->r, c->g, c->b);
}
a program D:
import std.stdio;
extern(C++)
{
class Color
{
uint r, g, b;
this(uint _r, uint _g, uint _b)
{
r = _r;
g = _g;
b = _b;
}
}
class Printer
{
@disable this();
static Printer getInstance();
final void print(Color c);
}
}
void main()
{
auto printer = Printer.getInstance();
Color c = new Color(42, 7, 19);
printer.print(c);
}
skompilować je z tych poleceń:
c++ -c my_core.cpp -o my_core.o
dmd main.d my_core.o -L-lstdc++
Ale kiedy biegnę ./main
, mam dziwne wyniki:
(113244372, 1, 42)
Co sprawiło, że myślę, że obiekty są przekazywane nieprawidłowo to po prostu prosty eksperyment. Po pierwsze, wpadłem mój program kilka razy i oto co zobaczyłam:
$ ./main
(266442332, 1, 42)
$ ./main
(234899036, 1, 42)
$ ./main
(109475420, 1, 42)
Więc pierwsza liczba wydaje się być wskaźnik do bloku pamięci. Szóste uczucie w połączeniu ze znajomością montażu powoduje, że myślę, że jest to wskaźnik do zmiennej this
.
A teraz, żeby potwierdzić moje dane nadal jest na swoim miejscu i te numery nie są jedynie przypadkowe te, dodałem dwa kolejne pola do mojego klasy Color
:
C++ lib:
#include <stdio.h>
class Color
{
public:
Color(unsigned int _r, unsigned int _g, unsigned int _b, unsigned int _u, unsigned int _v) : r(_r), g(_g), b(_b), u(_u), v(_v) {}
unsigned int r, g, b, u, v;
};
class Printer
{
public:
Printer() {}
~Printer() {}
static Printer* getInstance();
void print(Color *c);
};
Printer* Printer::getInstance()
{
return new Printer();
}
void Printer::print(Color *c)
{
printf("(%d, %d, %d, %d, %d)\n", c->r, c->g, c->b, c->u, c->v);
}
a program D:
import std.stdio;
extern(C++)
{
class Color
{
this(uint _r, uint _g, uint _b, uint _u, uint _v)
{
r = _r;
g = _g;
b = _b;
u = _u;
v = _v;
}
uint r, g, b, u, v;
}
class Printer
{
@disable this();
static Printer getInstance();
final void print(Color c);
}
}
void main()
{
auto printer = Printer.getInstance();
Color c = new Color(42, 7, 19, 499, 727);
printer.print(c);
}
a wyjścia są:
$ ./main
(90379876, 1, 42, 7, 19)
$ ./main
(79758948, 1, 42, 7, 19)
$ ./main
(74901092, 1, 42, 7, 19)
$ ./main
(217458276, 1, 42, 7, 19)
$ ./main
(238933604, 1, 42, 7, 19)
Próbowałem już skompilować mój program z kompilatorami DMD i LDC, ale oba zapewniły mi dokładnie to samo zachowanie.
UPD: Co jeszcze bardziej interesujące i (prawdopodobnie) wskazując, gdzie leży problem, to fakt, że obiekty stworzone w C++ lib są przekazywane pomiędzy D i C++ poprawnie.
Aby to udowodnić, stworzyłem "metody fabryki" w moim Color
klasy:
static Color* create(unsigned int _r, unsigned int _g, unsigned int _b, unsigned int _u, unsigned int _v) {
return new Color(_r, _g, _b, _u, _v);
}
a następnie w programie D:
Color c = Color.create(42, 7, 19, 499, 727);
printer.print(c);
tak aby obiekt c
pochodzi z C++ biblioteki zostaje przekazany do obiektu printer
, utworzonego w bibliotece C++ i ten transfer jest wykonywany w programie D.
a wyniki są niespodziewanie poprawne:
$ ./main
(42, 7, 19, 499, 727)
jestem brakuje koncepcji C++ i D współdziałanie czy jest to błąd w dwóch kompilatorów D (niepewnie)?
AFAIK to jest zgodne z projektem. D jest zdolny do połączenia z C++, ale nie może samodzielnie tworzyć obiektów C++ (a obiekty D mają inny układ binarny). Używanie metody fabrycznej wydaje się poprawne. –