mirror of
https://github.com/boostorg/openmethod.git
synced 2026-01-25 06:22:12 +00:00
110 lines
3.7 KiB
Plaintext
110 lines
3.7 KiB
Plaintext
:exampledir: ../example
|
|
|
|
[#basics]
|
|
|
|
An _open-method_ is a free-standing function that has one or more _virtual_
|
|
_parameters_. When it is called, it forwards to an _overrider_ selected from a
|
|
set by examining the dynamic types of the virtual parameters.
|
|
|
|
If this sounds like a virtual function, that's because an open-method
|
|
with one virtual parameter is equivalent to a virtual function - with one big
|
|
difference: it exists outside of classes.
|
|
|
|
A virtual parameter is in the form `virtual_ptr<Class>`. It is a pointer-like
|
|
class that points to an instance of `Class`. `virtual_ptr` is defined in the library's main namespace,
|
|
`boost::openmethod`.
|
|
|
|
To create an open-method that implements the `postfix` operation, we use the
|
|
xref:BOOST_OPENMETHOD.adoc[BOOST_OPENMETHOD] macro:
|
|
|
|
```c++
|
|
BOOST_OPENMETHOD(
|
|
postfix, (virtual_ptr<const Node> node, std::ostream& os), void);
|
|
```
|
|
|
|
`postfix` is the method's name. It takes one virtual parameter, `node`, and one
|
|
non-virtual parameter, `os`. It returns `void`. The macro generates the
|
|
following function:
|
|
|
|
```c++
|
|
inline auto postfix(virtual_ptr<const Node> node, std::ostream& os) -> void {
|
|
// examine the type of *node
|
|
// select an overrider
|
|
// call it
|
|
}
|
|
```
|
|
|
|
Before we can call the method, we need to define overriders. For that we use the
|
|
xref:BOOST_OPENMETHOD_OVERRIDE.adoc[BOOST_OPENMETHOD_OVERRIDE] macro:
|
|
|
|
[source,cpp]
|
|
----
|
|
include::{examplesdir}/ast.cpp[tag=variable_overrider]
|
|
----
|
|
|
|
The overrider must have virtual parameters in the same positions as in the
|
|
method. The classes in the method's virtual parameters must be accessible,
|
|
non-ambiguous bases of the classes in the overrider. Note that this rules out
|
|
repeated inheritance. Apart from this restriction, multiple and virtual
|
|
inheritance are supported.
|
|
|
|
The non-virtual parameters must have exactly the same types as in the method.
|
|
|
|
Let's look at another overrider:
|
|
|
|
[source,cpp]
|
|
----
|
|
include::{examplesdir}/ast.cpp[tag=plus_overrider]
|
|
----
|
|
|
|
This one calls `postfix` recursively to print the left and right
|
|
sub-expressions. Note that we call the method just like an ordinary function.
|
|
|
|
`postfix` expects a `virtual_ptr<const Node>`, and we are passing it a _plain_
|
|
_reference_ to a `Node` object. This works because `virtual_ptr` has conversion
|
|
constructors from plain references or pointers to objects, or from other
|
|
`virtual_ptr`{empty}s.
|
|
|
|
There are two more things we need to do.
|
|
|
|
OpenMethod is a library, not a compiler. It needs to be informed of all the
|
|
classes that may be used as virtual parameters, and in method calls, and their
|
|
inheritance relationships. We provide that information with the
|
|
xref:BOOST_OPENMETHOD_CLASSES.adoc[BOOST_OPENMETHOD_CLASSES] macro:
|
|
|
|
|
|
[source,cpp]
|
|
----
|
|
include::{examplesdir}/ast.cpp[tag=class_registration]
|
|
----
|
|
|
|
Classes can be registered multiple times, in any order, and incrementally. Every
|
|
direct base of a class must appear together with it in at least one call to
|
|
`BOOST_OPENMETHOD_CLASSES`. This enables the library to deduce the complete
|
|
inheritance lattice.
|
|
|
|
The constructs used in this example require the classes to be polymorphic, in
|
|
the standard C++ sense, i.e. they must have at least one virtual function. The
|
|
library can also be used with non-polymorphic classes, with some restrictions.
|
|
|
|
Finally, we need to call `boost::openmethod::initialize()` before the first call
|
|
to an open-method. This builds the dispatch tables used during method calls. It
|
|
is typically done once, at the very beginning of main, and requires the
|
|
inclusion of `<boost/openmethod/initialize.hpp>`.
|
|
|
|
```c++
|
|
#include <boost/openmethod/initialize.hpp>
|
|
|
|
int main() {
|
|
boost::openmethod::initialize();
|
|
// ...
|
|
}
|
|
```
|
|
|
|
Putting it all together:
|
|
|
|
[source,cpp]
|
|
----
|
|
include::{examplesdir}/ast.cpp[tag=content]
|
|
----
|