mirror of
https://github.com/pybind/pybind11.git
synced 2026-04-19 22:39:09 +00:00
support for overriding virtual functions
This commit is contained in:
@@ -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
82
example/example12.cpp
Normal 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
31
example/example12.py
Normal 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)
|
||||
@@ -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>());
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user