Here is an abstract base class and a concrete subclass, which I would like to expose to Python via Cython:
class NodeDistance {
protected:
const Graph& G;
public:
NodeDistance(const Graph& G);
virtual ~NodeDistance();
virtual void preprocess() = 0;
virtual double distance(node u, node v) = 0;
};
class NeighborhoodDistance: public NetworKit::NodeDistance {
public:
NeighborhoodDistance(const Graph& G);
virtual ~NeighborhoodDistance();
virtual void preprocess();
virtual double distance(node u, node v);
};
This is my first attempt at declaring the interface of the classes for Cython. To avoid naming conflicts between the cppclass
es and the Python wrapper classes, I declare every Class
as _Class
, followed by its proper name "Namespace::Class"
.
cdef extern from "../cpp/distmeasures/NodeDistance.h":
cdef cppclass _NodeDistance "NetworKit::NodeDistance":
_NodeDistance(_Graph G) except +
void preprocess() except +
double distance(node, node) except +
cdef extern from "../cpp/distmeasures/NeighborhoodDistance.h":
cdef cppclass _NeighborhoodDistance(_NodeDistance) "NetworKit::NeighborhoodDistance":
_NeighborhoodDistance(_Graph G) except +
void preprocess() except +
double distance(node, node) except +
But now I get a syntax error when trying to express that _NeighborhoodDistance
is a subclass of _NodeDistance
. What did I do wrong?
Error compiling Cython file:
------------------------------------------------------------
...
void preprocess() except +
double distance(node, node) except +
cdef extern from "../cpp/distmeasures/NeighborhoodDistance.h":
cdef cppclass _NeighborhoodDistance(_NodeDistance) "NetworKit::NeighborhoodDistance":
^
------------------------------------------------------------
_NetworKit.pyx:1698:52: Syntax error in C++ class definition
I don't think you can even express the combination of base class and renaming in Cython 0.20.1. You can either not rename the classes and specify the namespace in the cdef extern from
:
# C++ classes shown at the end
cdef extern from "example.hpp" namespace "example":
cdef cppclass Base:
void some_method() except +
cdef cppclass Derived(Base):
void some_method() except +
... or not specify the inheritance:
cdef extern from "example.hpp" namespace "example":
cdef cppclass Base "example::Base":
void some_method() except +
cdef cppclass Derived "example::Derived":
void some_method() except +
Either way, Cython doesn't seem to understand C++ inheritance fully, and you need an explicit cast:
def test():
cdef Derived d
cdef Base *p = <Base *>&d
p.some_method()
This is ugly because the cast effectively turns off typechecking in C++, but with care it can be used safely. (There are other circumstances where Cython's typechecking requires casts that are not necessary in C/C++, which is quite unfortunate.)
For reference, here are the classes I used:
// example.hpp
#include <cstdio>
namespace example {
struct Base {
virtual void some_method() = 0;
virtual ~Base() = 0;
};
struct Derived {
virtual void some_method()
{
std::puts("Hello!");
}
~Derived()
{
}
};
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With