Elegancko wywołaj C++ z C
Tworzymy jakiś projekt w zwykły C
(C99). Ale mamy jedną bibliotekę jako kody źródłowe (biblioteka matematyczna) w C++
. Potrzebujemy tej biblioteki, więc chciałbym zapytać, jaki jest najbardziej elegancki sposób integracji tych kodów źródłowych?
Stosunek wielkości C
i C++
jest 20:1
, więc przejście do C++
nie jest opcją. Powinniśmy użyć biblioteki statycznej? / Align = "left" / (Wszystko jest na Windows).
4 answers
EDIT: bazując na dyskusji w komentarzu, powinienem zauważyć, że rozdzielanie rzeczy na zgodne z C struct duck
i pochodne class Duck
jest prawdopodobnie niepotrzebne. Prawdopodobnie można bezpiecznie załadować implementację do struct duck
i wyeliminować class Duck
, eliminując w ten sposób real(…)
. Ale nie znam C++ na tyle dobrze (w szczególności, sposób, w jaki współdziała z uniwersum C), aby dać ostateczną odpowiedź na to pytanie.
Nie ma powodu, dla którego nie możesz po prostu połączyć całego kodu C i C++ razem w jedną całość.
Interfejs do kodu C++ wymaga zawinięcia API C++ w API C. Można to zrobić deklarując kilka funkcji wewnątrz extern "C" { ... }
podczas kompilacji kodu C++ oraz bez deklaracji extern podczas kompilacji kodu klienta C. Np.:
#ifdef __cplusplus
extern "C" {
#endif
typedef struct duck duck;
duck* new_duck(int feet);
void delete_duck(duck* d);
void duck_quack(duck* d, float volume);
#ifdef __cplusplus
}
#endif
Możesz zdefiniować strukturę kaczki w swoim źródle C++, a nawet dziedziczyć z niej prawdziwą klasę Duck
:
struct duck { };
class Duck : public duck {
public:
Duck(int feet);
~Duck();
void quack(float volume);
};
inline Duck* real(duck* d) { return static_cast<Duck*>(d); }
duck* new_duck(int feet) { return new Duck(feet); }
void delete_duck(duck* d) { delete real(d); }
void duck_quack(duck* d, float volume) { real(d)->quack(volume); }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-18 23:28:59
Biblioteka matematyczna C++ może być zaimplementowana w klasach użyteczności for (tylko członkowie statyczni). W tym przypadku można przyjąć znacznie prostsze podejście:
class FPMath {
public:
static double add(double, double);
static double sub(double, double);
static double mul(double, double);
static double div(double, double);
};
Nagłówek interfejsu C będzie wtedy:
double FPMath_add(double, double);
double FPMath_sub(double, double);
double FPMath_mul(double, double);
double FPMath_div(double, double);
I odpowiadającą jej implementacją może być:
double FPMath_add(double a, double b) { return FPMath::add(a, b); }
double FPMath_sub(double a, double b) { return FPMath::sub(a, b); }
double FPMath_mul(double a, double b) { return FPMath::mul(a, b); }
double FPMath_div(double a, double b) { return FPMath::div(a, b); }
Ale może to jest oczywiste....Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-06 13:55:57
Jedynym powodem, dla którego chcemy dziedziczyć po strukturze duck, byłoby ujawnienie niektórych jej atrybutów W C API, co i tak jest ogólnie uważane za zły styl. Bez dziedziczenia Twój nagłówek C wyglądałby tak:
struct Duck;
struct Duck* new_Duck(int feet);
void delete_Duck(struct Duck* d);
void Duck_quack(struct Duck* d, float volume);
I to byłaby odpowiednia implementacja, bez potrzeby odlewów typu:
extern "C" {
#include "Duck.h"
}
class Duck {
public:
Duck(int feet) : {}
~Duck() {}
void quack(float volume) {}
};
struct Duck* new_Duck(int feet) { return new Duck(feet); }
void delete_Duck(struct Duck* d) { delete d; }
void Duck_quack(struct Duck* d, float volume) { d->quack(volume); }
W ten sam sposób można utworzyć C API dla interfejsu C++ (pure virtual class) i jego implementacji. W takim przypadku tylko konstruktor musi być oparty na konkretną realizację (np. new_RubberDuck(2)). Destruktor i wszystkie inne funkcje będą działać automatycznie na poprawnej implementacji, tak samo jak w C++.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-06 13:29:58
Istnieje sposób na stworzenie "hakera", który pozwala na bezpośrednie wywołanie funkcji Członkowskich niektórych obiektów.
Pierwszą rzeczą, którą musisz zrobić, jest utworzenie extern "C"
funkcji fabrycznej, która zwraca wskaźnik (jako void*
) do obiektu.
Drugą rzeczą, której potrzebujesz, jest zniekształcona nazwa funkcji członka.
Następnie można wywołać funkcję używając zniekształconej nazwy i przekazać wskaźnik zwrócony z funkcji fabrycznej jako pierwszy kłótnia.
Zastrzeżenia:
- oczywiście nie będzie działać wywołanie funkcji członka, która chce innych obiektów, referencji lub innych rzeczy C++, lub funkcji zwracających obiekty lub typy niezgodne z typami C
- nie będzie działać na wirtualnych funkcjach członkowskich, i prawdopodobnie nie na obiektach z funkcjami wirtualnymi w nich, nawet jeśli nie jest to funkcja wirtualna wywoływana
- nazwa zniekształcona musi być prawidłowym symbolem C
- Any many many więcej...
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-09 11:48:25