Skip to content

Commit

Permalink
expand documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
wlav committed Oct 26, 2017
1 parent 57d79f5 commit d0a0234
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 93 deletions.
128 changes: 128 additions & 0 deletions doc/source/classes.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
Classes
=======

Both Python and C++ support object-oriented code through classes and thus
it is logical to expose C++ classes as Python ones, including the full
inheritence hierarchy.

The C++ code used for the examples below can be found
:doc:`here <cppyy_features_header>`, and it is assumed that that code is
loaded at the start of any session.
Download it, save it under the name ``features.h``, and load it:

.. code-block:: python
>>> import cppyy
>>> cppyy.include('features.h')
The basics
----------

All bound C++ code starts off from the global C++ namespace, represented in
Python by ``gbl``.
This namespace, as any other namespace, is treated as a module after it has
been loaded.
Thus, we can import C++ classes that live underneath it:

.. code-block:: python
>>> from cppyy.gbl import Concrete
>>> Concrete
<class cppyy.gbl.Concrete at 0x2058e30>
>>>
Placing classes in the same structure as imposed by C++ guarantees identity,
even if multiple Python modules bind the same class.
There is, however, no necessity to expose that structure to end-users: when
developing a Python package that exposes C++ classes through ``cppyy``,
consider ``cppyy.gbl`` an "internal" module, and expose the classes in any
structure you see fit.

A bound C++ class *is* a Python class and can be used in any way a Python
class can.
For example, we can ask for ``help()``:

.. code-block:: python
>>> help(Concrete)
Help on class Concrete in module gbl:
class Concrete(Abstract)
| Method resolution order:
| Concrete
| Abstract
| ObjectProxy
| __builtin__.object
|
| Methods defined here:
|
| __assign__(self, const Concrete&)
| Concrete& Concrete::operator=(const Concrete&)
|
| __init__(self, *args)
| Concrete::Concrete(int n = 42)
| Concrete::Concrete(const Concrete&)
|
etc. ....
The output of help shows the inheritance hierarchy, constructors, public
methods, and public data.
For example, ``Concrete`` inherits from ``Abstract`` and it has
a constructor that takes an ``int`` argument, with a default value of 42.
Consider:

.. code-block:: python
>>> from cppyy.gbl import Abstract
>>> issubclass(Concrete, Abstract)
True
>>> a = Abstract()
Traceback (most recent call last):
File "<console>", line 1, in <module>
TypeError: cannot instantiate abstract class 'Abstract'
>>> c = Concrete()
>>> isinstance(c, Concrete)
True
>>> isinstance(c, Abstract)
True
>>> d = Concrete(13)
>>>
Just like in C++, interface classes that define pure virtual methods, such
as ``Abstract`` does, can not be instantiated, but their concrete
implementations can.
As the output of ``help`` showed, the ``Concrete`` constructor takes
an integer argument, that by default is 42.
The ``Concrete`` instances have a public data member ``m_int`` that
is treated as a Python property, albeit a typed one:

.. code-block:: python
>>> c.m_int, d.m_int
(42, 13)
>>> c.m_int = 3.14 # a float does not fit in an int
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: int/long conversion expects an integer object
>>> c.m_int = int(3.14)
>>> c.m_int, d.m_int
(3, 13)
>>>
Just as classes, C++ methods are represented as Python ones.
They are first-class objects and can, for example, be bound to an instance.
If a method is virtual in C++, the proper concrete method is called, whether
or not the concrete class is bound.
Similarly, if all classes are bound, the normal Python rules apply:

.. code-block:: python
>>> c.abstract_method()
called Concrete::abstract_method
>>> c.concrete_method()
called Concrete::concrete_method
>>> m = c.abstract_method
>>> m()
called Concrete::abstract_method
>>>
4 changes: 2 additions & 2 deletions doc/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@
# built documents.
#
# The short X.Y version.
version = '0.3'
version = '0.8'
# The full version, including alpha/beta/rc tags.
release = '0.3'
release = '0.8'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
24 changes: 16 additions & 8 deletions doc/source/cppyy_features_header.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,29 @@ File features.h
unsigned int gUint = 0;

//-----
class AbstractClass {
class Abstract {
public:
virtual ~AbstractClass() {}
virtual ~Abstract() {}
virtual void abstract_method() = 0;
virtual void concrete_method() = 0;
};

void Abstract::concrete_method() {
std::cout << "called Abstract::concrete_method" << std::endl;
}

//-----
class ConcreteClass : AbstractClass {
class Concrete : Abstract {
public:
ConcreteClass(int n=42) : m_int(n), m_const_int(17) {}
~ConcreteClass() {}
Concrete(int n=42) : m_int(n), m_const_int(17) {}
~Concrete() {}

virtual void abstract_method() {
std::cout << "called concrete method" << std::endl;
std::cout << "called Concrete::abstract_method" << std::endl;
}

virtual void concrete_method() {
std::cout << "called Concrete::concrete_method" << std::endl;
}

void array_method(int* ad, int size) {
Expand All @@ -39,7 +47,7 @@ File features.h
std::cout << std::endl;
}

AbstractClass* show_autocast() {
Abstract* show_autocast() {
return this;
}

Expand All @@ -55,7 +63,7 @@ File features.h

namespace Namespace {

class ConcreteClass {
class Concrete {
public:
class NestedClass {
public:
Expand Down

0 comments on commit d0a0234

Please sign in to comment.