support for overriding virtual functions

This commit is contained in:
Wenzel Jakob
2015-10-01 16:46:03 +02:00
parent 04358b02ed
commit a2f6fde0dc
12 changed files with 222 additions and 91 deletions

View File

@@ -20,6 +20,7 @@ void init_ex8(py::module &);
void init_ex9(py::module &);
void init_ex10(py::module &);
void init_ex11(py::module &);
void init_ex12(py::module &);
PYTHON_PLUGIN(example) {
py::module m("example", "pybind example plugin");
@@ -35,6 +36,7 @@ PYTHON_PLUGIN(example) {
init_ex9(m);
init_ex10(m);
init_ex11(m);
init_ex12(m);
return m.ptr();
}

82
example/example12.cpp Normal file
View File

@@ -0,0 +1,82 @@
/*
example/example12.cpp -- overriding virtual functions from Python
Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#include "example.h"
#include <pybind/functional.h>
/* This is an example class that we'll want to be able to extend from Python */
class Example12 {
public:
Example12(int state) : state(state) {
cout << "Constructing Example12.." << endl;
}
~Example12() {
cout << "Destructing Example12.." << endl;
}
virtual int run(int value) {
std::cout << "Original implementation of Example12::run(state=" << state
<< ", value=" << value << ")" << std::endl;
return state + value;
}
virtual void pure_virtual() = 0;
private:
int state;
};
/* This is a wrapper class that must be generated */
class PyExample12 : public Example12 {
public:
using Example12::Example12; /* Inherit constructors */
virtual int run(int value) {
/* Generate wrapping code that enables native function overloading */
PYBIND_OVERLOAD(
int, /* Return type */
Example12, /* Parent class */
run, /* Name of function */
value /* Argument(s) */
);
}
virtual void pure_virtual() {
PYBIND_OVERLOAD_PURE(
void, /* Return type */
Example12, /* Parent class */
pure_virtual /* Name of function */
/* This function has no arguments */
);
}
};
int runExample12(Example12 *ex, int value) {
return ex->run(value);
}
void runExample12Virtual(Example12 *ex) {
ex->pure_virtual();
}
void init_ex12(py::module &m) {
/* Important: use the wrapper type as a template
argument to class_<>, but use the original name
to denote the type */
py::class_<PyExample12>(m, "Example12")
/* Declare that 'PyExample12' is really an alias for the original type 'Example12' */
.alias<Example12>()
.def(py::init<int>())
/* Reference original class in function definitions */
.def("run", &Example12::run)
.def("pure_virtual", &Example12::pure_virtual);
m.def("runExample12", &runExample12);
m.def("runExample12Virtual", &runExample12Virtual);
}

31
example/example12.py Normal file
View File

@@ -0,0 +1,31 @@
#!/usr/bin/env python
from __future__ import print_function
import sys
sys.path.append('.')
from example import Example12, runExample12, runExample12Virtual
class ExtendedExample12(Example12):
def __init__(self, state):
super(ExtendedExample12, self).__init__(state + 1)
self.data = "Hello world"
def run(self, value):
print('ExtendedExample12::run(%i), calling parent..' % value)
return super(ExtendedExample12, self).run(value + 1)
def pure_virtual(self):
print('ExtendedExample12::pure_virtual(): %s' % self.data)
ex12 = Example12(10)
print(runExample12(ex12, 20))
try:
runExample12Virtual(ex12)
except Exception as e:
print("Caught expected exception: " + str(e))
ex12p = ExtendedExample12(10)
print(runExample12(ex12p, 20))
runExample12Virtual(ex12p)

View File

@@ -37,28 +37,6 @@ void dog_bark(const Dog &dog) {
dog.bark();
}
class Example5 {
public:
Example5(py::handle self, int state)
: self(self), state(state) {
cout << "Constructing Example5.." << endl;
}
~Example5() {
cout << "Destructing Example5.." << endl;
}
void callback(int value) {
py::gil_scoped_acquire gil;
cout << "In Example5::callback() " << endl;
py::object method = self.attr("callback");
method.call(state, value);
}
private:
py::handle self;
int state;
};
bool test_callback1(py::object func) {
func.call();
return false;
@@ -69,16 +47,11 @@ int test_callback2(py::object func) {
return result.cast<int>();
}
void test_callback3(Example5 *ex, int value) {
py::gil_scoped_release gil;
ex->callback(value);
}
void test_callback4(const std::function<int(int)> &func) {
void test_callback3(const std::function<int(int)> &func) {
cout << "func(43) = " << func(43)<< std::endl;
}
std::function<int(int)> test_callback5() {
std::function<int(int)> test_callback4() {
return [](int i) { return i+1; };
}
@@ -99,8 +72,4 @@ void init_ex5(py::module &m) {
m.def("test_callback2", &test_callback2);
m.def("test_callback3", &test_callback3);
m.def("test_callback4", &test_callback4);
m.def("test_callback5", &test_callback5);
py::class_<Example5>(m, "Example5")
.def(py::init<py::object, int>());
}

View File

@@ -24,29 +24,17 @@ from example import test_callback1
from example import test_callback2
from example import test_callback3
from example import test_callback4
from example import test_callback5
from example import Example5
def func1():
print('Callback function 1 called!')
def func2(a, b, c, d):
print('Callback function 2 called : ' + str(a) + ", " + str(b) + ", " + str(c) + ", "+ str(d))
return c
class MyCallback(Example5):
def __init__(self, value):
Example5.__init__(self, self, value)
def callback(self, value1, value2):
print('got callback: %i %i' % (value1, value2))
return d
print(test_callback1(func1))
print(test_callback2(func2))
callback = MyCallback(3)
test_callback3(callback, 4)
test_callback4(lambda i: i+1)
f = test_callback5()
test_callback3(lambda i: i + 1)
f = test_callback4()
print("func(43) = %i" % f(43))