mirror of
https://github.com/boostorg/openmethod.git
synced 2026-01-19 16:32:12 +00:00
100 lines
3.3 KiB
Plaintext
100 lines
3.3 KiB
Plaintext
:example: ../examples/rolex
|
|
|
|
[#Headers]
|
|
|
|
Typically, `BOOST_OPENMETHOD` is used in headers, while
|
|
`BOOST_OPENMETHOD_CLASSES` and `BOOST_OPENMETHOD_OVERRIDE` are used in
|
|
implementation files.
|
|
|
|
Let's use a payroll application as an example. We have two roles: `Employee` and
|
|
`Salesman`, and a `pay` method that computes the monthly pay of an employee. We
|
|
want to override and call `pay` from multiple translation units, so we put it in
|
|
a header:
|
|
|
|
[source,c++]
|
|
----
|
|
include::{example}/1/roles.hpp[tag=content]
|
|
----
|
|
|
|
`BOOST_OPENMETHOD` _defines_ an inline function, so it can be called only once
|
|
in a translation unit. The include guards see to this.
|
|
|
|
Let's write the override for "just" employees - they get a fixed salary.
|
|
`BOOST_OPENMETHOD_OVERRIDE` _adds_ an overrider to the method. We don't want to
|
|
add the same multiple times; that would create an ambiguity. Thus it should go
|
|
in an implementation file:
|
|
|
|
[source,c++]
|
|
----
|
|
include::{example}/1/employee.cpp[tag=content]
|
|
----
|
|
|
|
Salesmen get a salary like employees, and on top get a commission on their
|
|
sales. The `next` function, available only in the body of an overrider, calls
|
|
the next most specialized overrider. It is similar to `super` in other
|
|
languages, except that it does not stand for an object, but for an overrider.
|
|
|
|
[source,c++]
|
|
----
|
|
include::{example}/1/salesman.cpp[tag=content]
|
|
----
|
|
|
|
Paytime!
|
|
|
|
[source,c++]
|
|
----
|
|
include::{example}/1/main.cpp[tag=content]
|
|
----
|
|
|
|
In the previous example, we used `next` to call the super-overrider. We can also
|
|
call an overrider directly. To do this, we can declare the overrider in the
|
|
header, and define it in an implementation file:
|
|
|
|
[source,c++]
|
|
----
|
|
include::{example}/2/roles.hpp[tag=content]
|
|
----
|
|
|
|
Unlike function declarations,
|
|
xref:BOOST_OPENMETHOD_DECLARE_OVERRIDER.adoc[BOOST_OPENMETHOD_DECLARE_OVERRIDER]
|
|
cannot appear multiple times in a translation unit with the same arguments.
|
|
Also, it requires the _method_ itself to be defined prior using this macro.
|
|
|
|
Overriders are placed in _overrider_ _containers_. An overrider container is a
|
|
class template named after the method, declared in the current namespace. It is
|
|
specialized for each overrider signature. Macro
|
|
xref:BOOST_OPENMETHOD_OVERRIDER.adoc[BOOST_OPENMETHOD_OVERRIDER] takes the same
|
|
arguments `BOOST_OPENMETHOD_OVERRIDE`, and expands to the corresponding
|
|
specialization of the overrider container. Containers have a static member
|
|
function `fn` that contains the body the overrider, provided by the user. We can
|
|
call the overrider for `Employee` like so:
|
|
|
|
[source,c++]
|
|
----
|
|
include::{example}/2/salesman.cpp[tag=content]
|
|
----
|
|
|
|
This is similar to a virtual function calling a base overrider. Virtual
|
|
functions don't have the equivalent of Smalltalk's or Python's `super`, but
|
|
OpenMethod does, it's `next`. It is almost always the right choice.
|
|
|
|
The exception is: when performance is critical, we may want to inline the call
|
|
to the base overrider.
|
|
xref:BOOST_OPENMETHOD_INLINE_OVERRIDE.adoc[BOOST_OPENMETHOD_INLINE_OVERRIDE]
|
|
defines the overrider as an inline function, and it can go in a header file:
|
|
|
|
[source,c++]
|
|
----
|
|
include::{example}/3/roles.hpp[tag=content]
|
|
----
|
|
|
|
With inlining the overrider for `Salesman` compiles to (clang-20, x64-linux):
|
|
|
|
[source,asm]
|
|
----
|
|
movsd xmm0, qword ptr [rsi + 8]
|
|
mulsd xmm0, qword ptr [rip + .LCPI1_0]
|
|
addsd xmm0, qword ptr [rip + .LCPI1_1]
|
|
ret
|
|
----
|