Files
openmethod/doc/virtual_ptr_alt.adoc
Jean-Louis Leroy 5e0fa8ee4b inception
2025-03-08 15:31:25 -05:00

77 lines
2.5 KiB
Plaintext

## Alternatives to virtual_ptr
Virtual arguments can be passed as plain references. In a method declaration,
parameters with a type decorated with `virtual_` are considered in overrider
selection (along with `virtual_ptr` parameters).
For example, the `poke` open-method in the Animals example can be rewritten as:
[source,c++]
----
include::{examplesdir}/virtual_.cpp[tag=virtual_parameter,indent=0]
int main() {
boost::openmethod::initialize();
Cat cat;
poke(std::cout, cat); // hiss
}
----
Note that `virtual_` is not used in the overrider. It is also removed from the
method's signature.
By itself, `virtual_` does not provide any benefits. Passing the virtual
argument by reference almost compiles to the same code as creating a
`virtual_ptr`, using it for one call, then throwing it way. The only difference
is that the virtual argument is passed as one pointer instead of two.
However, we can now customize how the vptr is obtained. When the method sees a
`virtual_` parameter, it looks for a `boost_openmethod_vptr` function that takes
the parameter (by const reference), and returns a `vptr_type`. If one is found,
it is called to obtain the vptr. The vptr for a specific registered class can be
obtained via a variable template `static_vptr`, nested in class `default_policy`
(more on policies below).
In the following example, we embed a vptr in the object, just like the vptr for
native virtual functions:
[source,c++]
----
include::{examplesdir}/virtual_.cpp[tag=virtual_intrusive,indent=0]
int main() {
boost::openmethod::initialize();
Cat cat;
poke(std::cout, cat); // hiss
}
----
NOTE: With this approach, classes need not be polymorphic. A virtual
destructor might be needed for correct destruction of objects, but it is not
required by the library.
The `with_vptr` CRTP class automates the creation and management of embedded
vptrs.
[source,c++]
----
include::{examplesdir}/virtual_.cpp[tag=with_vptr,indent=0]
int main() {
boost::openmethod::initialize();
Cat cat;
poke(std::cout, cat); // hiss
}
----
If `with_vptr` is passed only the class being defined, it adds a vptr to it, and
defines a `boost_openmethod_vptr` friend function. If more classes are passed,
they must be the direct bases of the class potentially involved in open-method
calls. Its constructor and destructor set the vptr to point to the v-table for
the class. `with_vptr` also takes care of registering the classes, so this time
the call to `BOOST_OPENMETHOD_CLASSES` is not needed.