Eu estou olhando para desenvolver um conjunto de APIs C que irá envolver nossas APIs C ++ existentes para acessar nossa lógica principal (escrita em C ++ orientada a objects). Esta será essencialmente uma API de cola que permite que nossa lógica C ++ possa ser usada por outras linguagens. Quais são alguns bons tutoriais, livros ou melhores práticas que introduzem os conceitos envolvidos no envolvimento do C em torno do C ++ orientado a objects?
Isso não é muito difícil de fazer à mão, mas dependerá do tamanho da sua interface. Os casos em que fiz isso foram para permitir o uso de nossa biblioteca C ++ a partir do código C puro, e assim o SWIG não ajudou muito. (Bem, talvez SWIG pode ser usado para fazer isso, mas eu não sou guru SWIG e parecia não-trivial)
Tudo o que acabamos fazendo foi:
Então, uma class como essa (header C ++)
class MyClass { public: explicit MyClass( std::string & s ); ~MyClass(); int doSomething( int j ); }
Mapearia para uma interface C assim (header C):
struct HMyClass; // An opaque type that we'll use as a handle typedef struct HMyClass HMyClass; HMyClass * myStruct_create( const char * s ); void myStruct_destroy( HMyClass * v ); int myStruct_doSomething( HMyClass * v, int i );
A implementação da interface ficaria assim (fonte C ++)
#include "MyClass.h" extern "C" { HMyClass * myStruct_create( const char * s ) { return reinterpret_cast( new MyClass( s ) ); } void myStruct_destroy( HMyClass * v ) { delete reinterpret_cast(v); } int myStruct_doSomething( HMyClass * v, int i ) { return reinterpret_cast(v)->doSomething(i); } }
Derivamos nossa alça opaca da class original para evitar a necessidade de qualquer vazamento, e (isso não parece funcionar com o meu complium atual). Temos que fazer o manipulador de uma estrutura como C não suporta classs.
Então isso nos dá a interface C básica. Se você quiser um exemplo mais completo mostrando uma maneira de integrar o tratamento de exceções, tente meu código no github: https://gist.github.com/mikeando/5394166
A parte divertida agora é garantir que você obtenha todas as bibliotecas C ++ necessárias vinculadas a sua biblioteca maior corretamente. Para o gcc (ou clang), isso significa apenas fazer o estágio final do link usando g ++.
Acho que a resposta de Michael Anderson está no caminho certo, mas minha abordagem seria diferente. Você precisa se preocupar com uma coisa extra: exceções. As exceções não fazem parte do C ABI, portanto, você não pode permitir que exceções sejam lançadas além do código C ++. Então seu header vai ficar assim:
#ifdef __cplusplus extern "C" { #endif void * myStruct_create( const char * s ); void myStruct_destroy( void * v ); int myStruct_doSomething( void * v, int i ); #ifdef __cplusplus } #endif
E o arquivo .cpp do seu wrapper ficará assim:
void * myStruct_create( const char * s ) { MyStruct * ms = NULL; try { /* The constructor for std::string may throw */ ms = new MyStruct(s); } catch (...) {} return static_cast( ms ); } void myStruct_destroy( void * v ) { MyStruct * ms = static_cast(v); delete ms; } int myStruct_doSomething( void * v, int i ) { MyStruct * ms = static_cast(v); int ret_value = -1; /* Assuming that a negative value means error */ try { ret_value = ms->doSomething(i); } catch (...) {} return ret_value; }
Melhor ainda: Se você sabe que tudo o que precisa como uma única instância do MyStruct, não corra o risco de lidar com pointers inválidos sendo passados para sua API. Faça algo assim:
static MyStruct * _ms = NULL; int myStruct_create( const char * s ) { int ret_value = -1; /* error */ try { /* The constructor for std::string may throw */ _ms = new MyStruct(s); ret_value = 0; /* success */ } catch (...) {} return ret_value; } void myStruct_destroy() { if (_ms != NULL) { delete _ms; } } int myStruct_doSomething( int i ) { int ret_value = -1; /* Assuming that a negative value means error */ if (_ms != NULL) { try { ret_value = _ms->doSomething(i); } catch (...) {} } return ret_value; }
Essa API é muito mais segura.
Mas, como Michael mencionou, as ligações podem ficar bastante complicadas.
Espero que isto ajude
Não é difícil expor o código C ++ para C, basta usar o padrão de design Fachada
Eu estou supondo que seu código C ++ é construído em uma biblioteca, tudo que você precisa fazer é fazer um módulo C em sua biblioteca C + + como uma fachada para sua biblioteca, juntamente com um arquivo de header C puro. O módulo C irá chamar as funções relevantes do C ++
Depois disso, seus aplicativos e biblioteca C terão access total ao C api exposto.
por exemplo, aqui está um módulo de Fachada de amostra
#include #include int doObjectOrientedStuff(int *arg1, int arg2, char *arg3) { Object obj = ObjectFactory->makeCppObj(arg3); // doing object oriented stuff here obj->doStuff(arg2); return obj->doMoreStuff(arg1); }
você então expõe esta function C como sua API e você pode usá-la livremente como um C lib sem se preocupar
// file name "libIntrface.h" extern int doObjectOrientedStuff(int *, int, char*);
Obviamente, este é um exemplo artificial, mas esta é a maneira mais fácil de expor uma biblioteca C ++ para C
Eu acho que você pode ser capaz de obter algumas idéias sobre direção e / ou possivelmente utilizar diretamente o SWIG . Eu pensaria que passar por cima de alguns dos exemplos, pelo menos, lhe daria uma idéia de que tipos de coisas a considerar ao envolver uma API em outra. O exercício pode ser benéfico.
SWIG é uma ferramenta de desenvolvimento de software que conecta programas escritos em C e C ++ com uma variedade de linguagens de programação de alto nível. O SWIG é usado com diferentes tipos de linguagens, incluindo linguagens de script comuns, como Perl, PHP, Python, Tcl e Ruby. A lista de idiomas suportados também inclui linguagens não scripting, como C #, Common Lisp (CLISP, Allegro CL, CFFI, UFFI), Java, Lua, Modula-3, OCAML, Octave e R. Também várias implementações de Scheme interpretadas e compiladas ( Guile, MzScheme, Chicken) são suportados. SWIG é mais comumente usado para criar ambientes de programação interpretados ou compilados de alto nível, interfaces de usuário e como uma ferramenta para testar e prototipar o software C / C ++. O SWIG também pode exportar sua tree de análise na forma de expressões XML e Lisp. SWIG pode ser livremente utilizado, distribuído e modificado para uso comercial e não comercial.
Basta replace o conceito de um object por um void *
(geralmente chamado de tipo opaco em bibliotecas orientadas a C) e reutilizar tudo o que você sabe de C ++.
Eu acho que usar o SWIG é a melhor resposta … não apenas evitar reinventar a roda, mas é confiável e também promover uma continuidade no desenvolvimento, em vez de triggersr o problema.
Problemas de alta frequência precisam ser resolvidos por uma solução de longo prazo.