Ho elaborato una risposta perfettamente gestibile. La pulizia che vorresti fosse interamente basata su quanto lavoro sei disposto a fare.
Innanzitutto, prendi la classe C++ e crea le funzioni di "wrapper" C per interfacciarlo con esso. Ad esempio, se abbiamo questa classe C++:
class MBR {
std::string filename;
public:
MBR (std::string filename);
const char *hexdump();
const char *imageType();
const char *bootCode();
const char *partitions();
private:
bool readFile(unsigned char *buffer, const unsigned int length);
};
Abbiamo quindi implementare queste funzioni C++:
#include "MBR.hpp"
using namespace std;
const void * initialize(char *filename)
{
MBR *mbr = new MBR(filename);
return (void *)mbr;
}
const char *hexdump(const void *object)
{
MBR *mbr;
static char retval[2048];
mbr = (MBR *)object;
strcpy(retval, mbr -> hexdump());
return retval;
}
const char *imageType(const void *object)
{
MBR *mbr;
static char retval[256];
mbr = (MBR *)object;
strcpy(retval, mbr -> imageType());
return retval;
}
L'intestazione ponte comprende quindi:
#ifndef ImageReader_hpp
#define ImageReader_hpp
#ifdef __cplusplus
extern "C" {
#endif
const void *initialize(char *filename);
const char *hexdump(const void *object);
const char *imageType(const void *object);
#ifdef __cplusplus
}
#endif
#endif /* ImageReader_hpp */
Da Swift, possiamo ora istanziare l'oggetto e interagire con esso in questo modo:
let cppObject = UnsafeMutablePointer<Void>(initialize(filename))
let type = String.fromCString(imageType(cppObject))
let dump = String.fromCString(hexdump(cppObject))
self.imageTypeLabel.stringValue = type!
self.dumpDisplay.stringValue = dump!
Quindi, come potete vedere, la soluzione (che in realtà è piuttosto semplice) è creare wrapper che istanzia un oggetto e restituiscono un puntatore a quell'oggetto. Questo può quindi essere passato di nuovo nelle funzioni wrapper che possono facilmente trattarlo come un oggetto conforme a quella classe e chiamare le funzioni membro.
rendendolo più pulito
Mentre questo è un inizio fantastico e dimostra che è completamente fattibile usare classi esistenti C++ con un ponte banale, può essere ancora più pulito.
Pulire questo significa semplicemente rimuovere il codice UnsafeMutablePointer<Void>
dal centro del nostro codice Swift e incapsularlo in una classe Swift. In sostanza, utilizziamo le stesse funzioni wrapper C/C++ ma le interfacciamo con una classe Swift. La classe Swift mantiene il riferimento all'oggetto e in pratica passa semplicemente tutto il metodo e attribuisce le chiamate di riferimento attraverso il bridge all'oggetto C++!
Dopo aver fatto questo, tutto il codice di bridging è completamente incapsulato nella classe Swift. Anche se stiamo ancora usando un bridge C, stiamo usando efficacemente oggetti C++ in modo trasparente, senza dover ricorrere a ricodificarli in Objective-C o Objective-C++.
ho personalmente fatto ricorso alla scrittura di semplici file wrapper Objective-C++ che espongono una classe Objective-C che riproduce tutte le pertinenti C++ chiama e semplicemente li inoltra a un'istanza in attesa della classe C++. Nel mio caso il numero di classi e chiamate C++ è piccolo, quindi non è particolarmente laborioso. Ma continuerò a difenderlo come una risposta nella speranza che qualcuno possa inventarsi qualcosa di meglio. – Tommy
Beh, è qualcosa ... Aspettiamo e vediamo (e speriamo). –
Ho ricevuto un suggerimento via IRC per scrivere una classe wrapper Swift che mantiene un puntatore vuoto all'oggetto C++ e espone i metodi richiesti che sono, in effetti, appena passati attraverso il bridge C e il puntatore all'oggetto. –