Doskonale!
Niezupełna, ale wystarczająca. Byłem w stanie zrobić lewę dla mojego własnego celu. Łączenie tego postu ze źródłami powiązanymi powyżej. To nie było łatwe, ponieważ jestem początkującym w Cython, ale potwierdzam, że jest to jedyny sposób, jaki mogłem znaleźć na stronie internetowej.
Wielkie dzięki dla was.
Żałuję, że nie mam tyle czasu wchodzić w szczegóły tekstowych, ale tutaj są moje pliki (może pomóc, aby uzyskać dodatkowy punkt widzenia, w jaki sposób umieścić to wszystko razem)
setup .py:
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
setup(
cmdclass = {'build_ext': build_ext},
ext_modules = [
Extension("elps",
sources=["elps.pyx", "src/ITestClass.cpp"],
libraries=["elp"],
language="c++",
)
]
)
TestClass:
#ifndef TESTCLASS_H_
#define TESTCLASS_H_
namespace elps {
class TestClass {
public:
TestClass(){};
virtual ~TestClass(){};
int getA() { return this->a; };
virtual int override_me() { return 2; };
int calculate(int a) { return a * this->override_me(); }
private:
int a;
};
} /* namespace elps */
#endif /* TESTCLASS_H_ */
ITestClass.h:
#ifndef ITESTCLASS_H_
#define ITESTCLASS_H_
// Created by Cython when providing 'public api' keywords
#include "../elps_api.h"
#include "../../inc/TestClass.h"
namespace elps {
class ITestClass : public TestClass {
public:
PyObject *m_obj;
ITestClass(PyObject *obj);
virtual ~ITestClass();
virtual int override_me();
};
} /* namespace elps */
#endif /* ITESTCLASS_H_ */
ITestClass.cpp:
#include "ITestClass.h"
namespace elps {
ITestClass::ITestClass(PyObject *obj): m_obj(obj) {
// Provided by "elps_api.h"
if (import_elps()) {
} else {
Py_XINCREF(this->m_obj);
}
}
ITestClass::~ITestClass() {
Py_XDECREF(this->m_obj);
}
int ITestClass::override_me()
{
if (this->m_obj) {
int error;
// Call a virtual overload, if it exists
int result = cy_call_func(this->m_obj, (char*)"override_me", &error);
if (error)
// Call parent method
result = TestClass::override_me();
return result;
}
// Throw error ?
return 0;
}
} /* namespace elps */
EDIT2: Uwaga na temat PURE metod wirtualnych (wydaje się być dość powracającym problemem). Jak pokazano w powyższym kodzie, w ten szczególny sposób, "TestClass :: override_me()" NIE MOŻE być czyste, ponieważ musi być możliwe wywołanie w przypadku, gdy metoda nie zostanie nadpisana w rozszerzonej klasie Pythona (aka: jeden nie wchodzi w "błąd"/"pominięcie nie znaleziono" w części "ITestClass :: override_me()").
Rozszerzenie: elps.pyx:
cimport cpython.ref as cpy_ref
cdef extern from "src/ITestClass.h" namespace "elps" :
cdef cppclass ITestClass:
ITestClass(cpy_ref.PyObject *obj)
int getA()
int override_me()
int calculate(int a)
cdef class PyTestClass:
cdef ITestClass* thisptr
def __cinit__(self):
##print "in TestClass: allocating thisptr"
self.thisptr = new ITestClass(<cpy_ref.PyObject*>self)
def __dealloc__(self):
if self.thisptr:
##print "in TestClass: deallocating thisptr"
del self.thisptr
def getA(self):
return self.thisptr.getA()
# def override_me(self):
# return self.thisptr.override_me()
cpdef int calculate(self, int a):
return self.thisptr.calculate(a) ;
cdef public api int cy_call_func(object self, char* method, int *error):
try:
func = getattr(self, method);
except AttributeError:
error[0] = 1
else:
error[0] = 0
return func()
wreszcie rozmowy python:
from elps import PyTestClass as TC;
a = TC();
print a.calculate(1);
class B(TC):
# pass
def override_me(self):
return 5
b = B()
print b.calculate(1)
ten powinien uczynić poprzednią pracę związaną z nadzieją więcej prosto do punktu, my dyskutujemy tutaj ..
EDYCJA: Z drugiej strony powyższy kod mógł zostać zoptymalizowany za pomocą "hasattr" zamiast bloku try/catch:
cdef public api int cy_call_func_int_fast(object self, char* method, bint *error):
if (hasattr(self, method)):
error[0] = 0
return getattr(self, method)();
else:
error[0] = 1
Powyższy kod ma oczywiście znaczenie tylko w przypadku, gdy nie przesłonimy metody "override_me".
Czy próbowałeś swojego kodu? –
tak, oczywiście. Zwraca 2. Czy potrzebujesz również źródła pyx (co jest całkiem błędne, ale nie mogłem go jeszcze znaleźć)? – ascobol
Nie, nie sądzę, że mogę pomóc. Myślę, że boost.python obsługuje to. –