Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
pybind11
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
open
pybind11
Commits
234f7c39
Commit
234f7c39
authored
Aug 17, 2017
by
Dean Moldovan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Test and document binding protected member functions
parent
9f6a636e
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
145 additions
and
0 deletions
+145
-0
docs/advanced/classes.rst
+75
-0
tests/test_class.cpp
+51
-0
tests/test_class.py
+19
-0
No files found.
docs/advanced/classes.rst
View file @
234f7c39
...
@@ -916,3 +916,78 @@ Python type created elsewhere.
...
@@ -916,3 +916,78 @@ Python type created elsewhere.
The file :file:`tests/test_local_bindings.cpp` contains additional examples
The file :file:`tests/test_local_bindings.cpp` contains additional examples
that demonstrate how ``py::module_local()`` works.
that demonstrate how ``py::module_local()`` works.
Binding protected member functions
==================================
It's normally not possible to expose ``protected`` member functions to Python:
.. code-block:: cpp
class A {
protected:
int foo() const { return 42; }
};
py::class_<A>(m, "A")
.def("foo", &A::foo); // error: 'foo' is a protected member of 'A'
On one hand, this is good because non-``public`` members aren't meant to be
accessed from the outside. But we may want to make use of ``protected``
functions in derived Python classes.
The following pattern makes this possible:
.. code-block:: cpp
class A {
protected:
int foo() const { return 42; }
};
class Publicist : public A { // helper type for exposing protected functions
public:
using A::foo; // inherited with different access modifier
};
py::class_<A>(m, "A") // bind the primary class
.def("foo", &Publicist::foo); // expose protected methods via the publicist
This works because ``&Publicist::foo`` is exactly the same function as
``&A::foo`` (same signature and address), just with a different access
modifier. The only purpose of the ``Publicist`` helper class is to make
the function name ``public``.
If the intent is to expose ``protected`` ``virtual`` functions which can be
overridden in Python, the publicist pattern can be combined with the previously
described trampoline:
.. code-block:: cpp
class A {
public:
virtual ~A() = default;
protected:
virtual int foo() const { return 42; }
};
class Trampoline : public A {
public:
int foo() const override { PYBIND11_OVERLOAD(int, A, foo, ); }
};
class Publicist : public A {
public:
using A::foo;
};
py::class_<A, Trampoline>(m, "A") // <-- `Trampoline` here
.def("foo", &Publicist::foo); // <-- `Publicist` here, not `Trampoline`!
.. note::
MSVC 2015 has a compiler bug (fixed in version 2017) which
requires a more explicit function binding in the form of
``.def("foo", static_cast<int (A::*)() const>(&Publicist::foo));``
where ``int (A::*)() const`` is the type of ``A::foo``.
tests/test_class.cpp
View file @
234f7c39
...
@@ -229,6 +229,57 @@ TEST_SUBMODULE(class_, m) {
...
@@ -229,6 +229,57 @@ TEST_SUBMODULE(class_, m) {
// This test is actually part of test_local_bindings (test_duplicate_local), but we need a
// This test is actually part of test_local_bindings (test_duplicate_local), but we need a
// definition in a different compilation unit within the same module:
// definition in a different compilation unit within the same module:
bind_local
<
LocalExternal
,
17
>
(
m
,
"LocalExternal"
,
py
::
module_local
());
bind_local
<
LocalExternal
,
17
>
(
m
,
"LocalExternal"
,
py
::
module_local
());
// test_bind_protected_functions
class
ProtectedA
{
protected
:
int
foo
()
const
{
return
value
;
}
private
:
int
value
=
42
;
};
class
PublicistA
:
public
ProtectedA
{
public
:
using
ProtectedA
::
foo
;
};
py
::
class_
<
ProtectedA
>
(
m
,
"ProtectedA"
)
.
def
(
py
::
init
<>
())
#if !defined(_MSC_VER) || _MSC_VER >= 1910
.
def
(
"foo"
,
&
PublicistA
::
foo
);
#else
.
def
(
"foo"
,
static_cast
<
int
(
ProtectedA
::*
)()
const
>
(
&
PublicistA
::
foo
));
#endif
class
ProtectedB
{
public
:
virtual
~
ProtectedB
()
=
default
;
protected
:
virtual
int
foo
()
const
{
return
value
;
}
private
:
int
value
=
42
;
};
class
TrampolineB
:
public
ProtectedB
{
public
:
int
foo
()
const
override
{
PYBIND11_OVERLOAD
(
int
,
ProtectedB
,
foo
,
);
}
};
class
PublicistB
:
public
ProtectedB
{
public
:
using
ProtectedB
::
foo
;
};
py
::
class_
<
ProtectedB
,
TrampolineB
>
(
m
,
"ProtectedB"
)
.
def
(
py
::
init
<>
())
#if !defined(_MSC_VER) || _MSC_VER >= 1910
.
def
(
"foo"
,
&
PublicistB
::
foo
);
#else
.
def
(
"foo"
,
static_cast
<
int
(
ProtectedB
::*
)()
const
>
(
&
PublicistB
::
foo
));
#endif
}
}
template
<
int
N
>
class
BreaksBase
{
public
:
virtual
~
BreaksBase
()
=
default
;
};
template
<
int
N
>
class
BreaksBase
{
public
:
virtual
~
BreaksBase
()
=
default
;
};
...
...
tests/test_class.py
View file @
234f7c39
...
@@ -176,3 +176,22 @@ def test_operator_new_delete(capture):
...
@@ -176,3 +176,22 @@ def test_operator_new_delete(capture):
"C delete "
+
sz_noalias
+
"
\n
"
+
"C delete "
+
sz_noalias
+
"
\n
"
+
"C delete "
+
sz_alias
+
"
\n
"
"C delete "
+
sz_alias
+
"
\n
"
)
)
def
test_bind_protected_functions
():
"""Expose protected member functions to Python using a helper class"""
a
=
m
.
ProtectedA
()
assert
a
.
foo
()
==
42
b
=
m
.
ProtectedB
()
assert
b
.
foo
()
==
42
class
C
(
m
.
ProtectedB
):
def
__init__
(
self
):
m
.
ProtectedB
.
__init__
(
self
)
def
foo
(
self
):
return
0
c
=
C
()
assert
c
.
foo
()
==
0
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment