virtual + inheritance example: remove multiple inheritance approach

It was already pretty badly intrusive, but it also appears to make MSVC
segfault.  Rather than investigating and fixing it, it's easier to just
remove it.
This commit is contained in:
Jason Rhinelander 2016-08-05 17:44:28 -04:00
parent 0ca96e2915
commit d6c365bcfa
4 changed files with 12 additions and 119 deletions

View File

@ -470,10 +470,6 @@ can now create a python class that inherits from ``Dog``:
See the file :file:`example-virtual-functions.cpp` for complete examples See the file :file:`example-virtual-functions.cpp` for complete examples
using both the duplication and templated trampoline approaches. using both the duplication and templated trampoline approaches.
The file also contains a more intrusive approach using multiple
inheritance, which may be useful in special situations with deep class
hierarchies to avoid code generation.
.. _macro_notes: .. _macro_notes:
General notes regarding convenience macros General notes regarding convenience macros

View File

@ -82,20 +82,12 @@ void runExampleVirtVirtual(ExampleVirt *ex) {
} }
// Inheriting virtual methods. We do three versions here: the repeat-everything version and the // Inheriting virtual methods. We do two versions here: the repeat-everything version and the
// templated trampoline versions mentioned in docs/advanced.rst, and also another version using // templated trampoline versions mentioned in docs/advanced.rst.
// multiple inheritance.
// //
// This latter approach has the advantage of generating substantially less code for deep // These base classes are exactly the same, but we technically need distinct
// hierarchies, but it requires intrusive changes of changing the wrapped classes to using virtual // classes for this example code because we need to be able to bind them
// inheritance, which itself requires constructor rewriting for any non-default virtual base class // properly (pybind11, sensibly, doesn't allow us to bind the same C++ class to
// constructors (most problematic is that constructors cannot be effectively inherited from a
// virtual base class). The example is kept here because it does work, and may be useful in limited
// cases, but the non-instrusive templated version is generally preferred.
//
// These base classes are all exactly the same (aside from the virtual inheritance for the MI
// version), but we technically need distinct classes for this example code because we need to be
// able to bind them properly (pybind11, sensibly, doesn't allow us to bind the same C++ class to
// multiple python classes). // multiple python classes).
class A_Repeat { class A_Repeat {
#define A_METHODS \ #define A_METHODS \
@ -129,13 +121,6 @@ class D_Repeat : public C_Repeat {
D_METHODS D_METHODS
}; };
// Base classes for multiple inheritance trampolines; note the added "virtual" inheritance. The
// classes are otherwise identical.
class A_MI { A_METHODS };
class B_MI : virtual public A_MI { B_METHODS };
class C_MI : virtual public B_MI { C_METHODS };
class D_MI : virtual public C_MI { D_METHODS };
// Base classes for templated inheritance trampolines. Identical to the repeat-everything version: // Base classes for templated inheritance trampolines. Identical to the repeat-everything version:
class A_Tpl { A_METHODS }; class A_Tpl { A_METHODS };
class B_Tpl : public A_Tpl { B_METHODS }; class B_Tpl : public A_Tpl { B_METHODS };
@ -213,31 +198,6 @@ public:
}; };
*/ */
// Inheritance approach 3: multiple inheritance with virtual base class inheritance. This requires
// declaration and compilation of exactly 7 methods (one per virtual method declaration or
// override), versus the 11 required above. On the other hand, if we need anything other than
// default constructors, this quickly becomes painful, and so this is of limited use.
class PyA_MI : virtual public A_MI {
public:
// Can't inherit constructors: we would have to duplicate constructors with an explicit
// initializer for each virtual base, which is a pain for anything but the default constructor.
int unlucky_number() override { PYBIND11_OVERLOAD_PURE(int, A_MI, unlucky_number, ); }
void say_something(unsigned times) override { PYBIND11_OVERLOAD(void, A_MI, say_something, times); }
};
class PyB_MI : public PyA_MI, virtual public B_MI {
public:
void say_something(unsigned times) override { PYBIND11_OVERLOAD(void, B_MI, say_something, times); }
double lucky_number() { PYBIND11_OVERLOAD(double, B_MI, lucky_number, ); }
int unlucky_number() { PYBIND11_OVERLOAD(int, B_MI, unlucky_number, ); }
};
class PyC_MI : public PyB_MI, virtual public C_MI {
public:
int unlucky_number() override { PYBIND11_OVERLOAD(int, C_MI, unlucky_number, ); }
double lucky_number() override { PYBIND11_OVERLOAD(double, C_MI, lucky_number, ); }
};
class PyD_MI : public PyC_MI, virtual public D_MI {
};
void initialize_inherited_virtuals(py::module &m) { void initialize_inherited_virtuals(py::module &m) {
// Method 1: repeat // Method 1: repeat
@ -266,19 +226,6 @@ void initialize_inherited_virtuals(py::module &m) {
py::class_<D_Tpl, std::unique_ptr<D_Tpl>, PyB_Tpl<D_Tpl>>(m, "D_Tpl", py::base<C_Tpl>()) py::class_<D_Tpl, std::unique_ptr<D_Tpl>, PyB_Tpl<D_Tpl>>(m, "D_Tpl", py::base<C_Tpl>())
.def(py::init<>()); .def(py::init<>());
// Method 3: MI
py::class_<A_MI, std::unique_ptr<A_MI>, PyA_MI>(m, "A_MI")
.def(py::init<>())
.def("unlucky_number", &A_MI::unlucky_number)
.def("say_something", &A_MI::say_something);
py::class_<B_MI, std::unique_ptr<B_MI>, PyB_MI>(m, "B_MI", py::base<A_MI>())
.def(py::init<>())
.def("lucky_number", &B_MI::lucky_number);
py::class_<C_MI, std::unique_ptr<C_MI>, PyC_MI>(m, "C_MI", py::base<B_MI>())
.def(py::init<>());
py::class_<D_MI, std::unique_ptr<D_MI>, PyD_MI>(m, "D_MI", py::base<C_MI>())
.def(py::init<>());
}; };

View File

@ -4,7 +4,7 @@ import sys
sys.path.append('.') sys.path.append('.')
from example import ExampleVirt, runExampleVirt, runExampleVirtVirtual, runExampleVirtBool from example import ExampleVirt, runExampleVirt, runExampleVirtVirtual, runExampleVirtBool
from example import A_Repeat, B_Repeat, C_Repeat, D_Repeat, A_MI, B_MI, C_MI, D_MI, A_Tpl, B_Tpl, C_Tpl, D_Tpl from example import A_Repeat, B_Repeat, C_Repeat, D_Repeat, A_Tpl, B_Tpl, C_Tpl, D_Tpl
class ExtendedExampleVirt(ExampleVirt): class ExtendedExampleVirt(ExampleVirt):
def __init__(self, state): def __init__(self, state):
@ -40,11 +40,6 @@ sys.stdout.flush()
class VI_AR(A_Repeat): class VI_AR(A_Repeat):
def unlucky_number(self): def unlucky_number(self):
return 99 return 99
class VI_AMI(A_MI):
def unlucky_number(self):
return 990
def say_something(self, times):
return A_MI.say_something(self, 2*times)
class VI_AT(A_Tpl): class VI_AT(A_Tpl):
def unlucky_number(self): def unlucky_number(self):
return 999 return 999
@ -52,17 +47,11 @@ class VI_AT(A_Tpl):
class VI_CR(C_Repeat): class VI_CR(C_Repeat):
def lucky_number(self): def lucky_number(self):
return C_Repeat.lucky_number(self) + 1.25 return C_Repeat.lucky_number(self) + 1.25
class VI_CMI(C_MI):
def lucky_number(self):
return 1.75
class VI_CT(C_Tpl): class VI_CT(C_Tpl):
pass pass
class VI_CCR(VI_CR): class VI_CCR(VI_CR):
def lucky_number(self): def lucky_number(self):
return VI_CR.lucky_number(self) * 10 return VI_CR.lucky_number(self) * 10
class VI_CCMI(VI_CMI):
def lucky_number(self):
return VI_CMI.lucky_number(self) * 100
class VI_CCT(VI_CT): class VI_CCT(VI_CT):
def lucky_number(self): def lucky_number(self):
return VI_CT.lucky_number(self) * 1000 return VI_CT.lucky_number(self) * 1000
@ -73,11 +62,6 @@ class VI_DR(D_Repeat):
return 123 return 123
def lucky_number(self): def lucky_number(self):
return 42.0 return 42.0
class VI_DMI(D_MI):
def unlucky_number(self):
return 1230
def lucky_number(self):
return -9.5
class VI_DT(D_Tpl): class VI_DT(D_Tpl):
def say_something(self, times): def say_something(self, times):
print("VI_DT says:" + (' quack' * times)) print("VI_DT says:" + (' quack' * times))
@ -87,12 +71,12 @@ class VI_DT(D_Tpl):
return -4.25 return -4.25
classes = [ classes = [
# A_Repeat, A_MI, A_Tpl, # abstract (they have a pure virtual unlucky_number) # A_Repeat, A_Tpl, # abstract (they have a pure virtual unlucky_number)
VI_AR, VI_AMI, VI_AT, VI_AR, VI_AT,
B_Repeat, B_MI, B_Tpl, B_Repeat, B_Tpl,
C_Repeat, C_MI, C_Tpl, C_Repeat, C_Tpl,
VI_CR, VI_CMI, VI_CT, VI_CCR, VI_CCMI, VI_CCT, VI_CR, VI_CT, VI_CCR, VI_CCT,
D_Repeat, D_MI, D_Tpl, VI_DR, VI_DMI, VI_DT D_Repeat, D_Tpl, VI_DR, VI_DT
] ]
for cl in classes: for cl in classes:

View File

@ -14,10 +14,6 @@ VI_AR:
hihihi hihihi
Unlucky = 99 Unlucky = 99
VI_AMI:
hihihihihihi
Unlucky = 990
VI_AT: VI_AT:
hihihi hihihi
Unlucky = 999 Unlucky = 999
@ -27,11 +23,6 @@ B says hi 3 times
Unlucky = 13 Unlucky = 13
Lucky = 7.00 Lucky = 7.00
B_MI:
B says hi 3 times
Unlucky = 13
Lucky = 7.00
B_Tpl: B_Tpl:
B says hi 3 times B says hi 3 times
Unlucky = 13 Unlucky = 13
@ -42,11 +33,6 @@ B says hi 3 times
Unlucky = 4444 Unlucky = 4444
Lucky = 888.00 Lucky = 888.00
C_MI:
B says hi 3 times
Unlucky = 4444
Lucky = 888.00
C_Tpl: C_Tpl:
B says hi 3 times B says hi 3 times
Unlucky = 4444 Unlucky = 4444
@ -57,11 +43,6 @@ B says hi 3 times
Unlucky = 4444 Unlucky = 4444
Lucky = 889.25 Lucky = 889.25
VI_CMI:
B says hi 3 times
Unlucky = 4444
Lucky = 1.75
VI_CT: VI_CT:
B says hi 3 times B says hi 3 times
Unlucky = 4444 Unlucky = 4444
@ -72,11 +53,6 @@ B says hi 3 times
Unlucky = 4444 Unlucky = 4444
Lucky = 8892.50 Lucky = 8892.50
VI_CCMI:
B says hi 3 times
Unlucky = 4444
Lucky = 175.00
VI_CCT: VI_CCT:
B says hi 3 times B says hi 3 times
Unlucky = 4444 Unlucky = 4444
@ -87,11 +63,6 @@ B says hi 3 times
Unlucky = 4444 Unlucky = 4444
Lucky = 888.00 Lucky = 888.00
D_MI:
B says hi 3 times
Unlucky = 4444
Lucky = 888.00
D_Tpl: D_Tpl:
B says hi 3 times B says hi 3 times
Unlucky = 4444 Unlucky = 4444
@ -102,11 +73,6 @@ B says hi 3 times
Unlucky = 123 Unlucky = 123
Lucky = 42.00 Lucky = 42.00
VI_DMI:
B says hi 3 times
Unlucky = 1230
Lucky = -9.50
VI_DT: VI_DT:
VI_DT says: quack quack quack VI_DT says: quack quack quack
Unlucky = 1234 Unlucky = 1234