Poza Boost.Python (który jest prawdopodobnie bardziej przyjaznym rozwiązaniem dla większych projektów, które wymagają odwzorowania klasy C++ typu "jeden do jednego" na klasy Pythona), można podać po stronie C++ interfejs C. Jest to jedno rozwiązanie wielu, więc ma własne kompromisy, ale przedstawię je dla korzyści tych, którzy nie znają tej techniki. Dla pełnego ujawnienia, przy takim podejściu nie byłby to interfejs C++ do Pythona, ale C++ do C do Pythona. Poniżej zamieściłem przykład, który spełnia twoje wymagania, aby pokazać ogólną ideę zewnętrznego "c" obiektu kompilatorów C++.
//YourFile.cpp (compiled into a .dll or .so file)
#include <new> //For std::nothrow
//Either include a header defining your class, or define it here.
extern "C" //Tells the compile to use C-linkage for the next scope.
{
//Note: The interface this linkage region needs to use C only.
void * CreateInstanceOfClass(void)
{
// Note: Inside the function body, I can use C++.
return new(std::nothrow) MyClass;
}
//Thanks Chris.
void DeleteInstanceOfClass (void *ptr)
{
delete(std::nothrow) ptr;
}
int CallMemberTest(void *ptr)
{
// Note: A downside here is the lack of type safety.
// You could always internally(in the C++ library) save a reference to all
// pointers created of type MyClass and verify it is an element in that
//structure.
//
// Per comments with Andre, we should avoid throwing exceptions.
try
{
MyClass * ref = reinterpret_cast<MyClass *>(ptr);
return ref->Test();
}
catch(...)
{
return -1; //assuming -1 is an error condition.
}
}
} //End C linkage scope.
można skompilować ten kod z
gcc -shared -o test.so test.cpp
#creates test.so in your current working directory.
W kodzie Pythona można zrobić coś takiego (Interactive wierszu od 2,7 pokazany):
>>> from ctypes import cdll
>>> stdc=cdll.LoadLibrary("libc.so.6") # or similar to load c library
>>> stdcpp=cdll.LoadLibrary("libstdc++.so.6") # or similar to load c++ library
>>> myLib=cdll.LoadLibrary("/path/to/test.so")
>>> spam = myLib.CreateInstanceOfClass()
>>> spam
[outputs the pointer address of the element]
>>> value=CallMemberTest(spam)
[does whatever Test does to the spam reference of the object]
Jestem pewien doładowania .Python robi coś podobnego pod maską, ale być może zrozumienie koncepcji niższego poziomu jest pomocne. Byłbym bardziej podekscytowany tą metodą, jeśli próbujesz uzyskać dostęp do funkcjonalności biblioteki C++, a mapowanie jeden-do-jednego nie było wymagane.
Więcej informacji na temat C/C++ interakcji sprawdzić tę stronę od Słońca: http://dsc.sun.com/solaris/articles/mixing.html#cpp_from_c
Rzeczywiście, jest to trochę uciążliwe, ale działa. Będziesz jednak szczególnie uważać na wyjątki. Nie sądzę, że można bezpiecznie założyć, że moduł 'ctypes' obsługuje funkcje C, które bardzo dobrze wyrzucają wyjątki. W szczególności instrukcja 'return new MyClass;' jest bardzo niebezpieczna, ponieważ może wywołać 'std :: bad_alloc'. –
Należy również dodać funkcję 'DestroyInstanceOfClass()'. –
To bardzo dobry punkt. Będę edytować przykład, aby użyć wariantu bez rzutowania. Inną sztuczką byłoby przechwycenie wszystkich wyjątków w bloku try w ciele C++ funkcji. – AudaAero