base
The following example uses a create
() method to
instantiate a new reference-counted object, with its initial pointer
or reference:
typedef x::ref<buttonObj> button; button b(button::create()); // ... b->click();
x::ref
's and x::ptr
's base
typedef actually
comes from an optional second parameter to the x::ref
and the x::ptr
template class, which defaults to x::ptrref_base
.
This can be overridden in two different ways. The first way is to
specify an additional parameter to the template:
class buttonBase; class buttonObj; typedef x::ref<buttonObj, buttonBase> button; typedef x::ptr<buttonObj, buttonBase> buttonptr; class buttonBase { public: template<typename ptrrefType> class objfactory { public: static ptrrefType create() { // ... } }; static const int default_width=50, default_height=50; };
The second way is to
specialize
x::base_type
and define a
type
class member:
class buttonObj; template<> struct x::base_type<buttonObj> { typedef buttonBase type; }; typedef x::ref<buttonObj> button; typedef x::ptr<buttonObj> buttonptr;
Specializing x::base_type
in this manner
ends up specifying the default second parameter to the
x::ref
and x::ptr
templates (also x::const_ref
and x::const_ptr
too).
With this specialization,
x::ref<buttonObj>
and
x::ref<buttonObj, buttonBase>
is the same type, with the second template parameter setting
the x::ref
's or the x::ptr
's base
member.
This specialization also takes effect when
constructing an x::ref
or an x::ptr
from
this
.
An x::ref
or an x::ptr
's create
() method invokes
base::objfactory<
(), where
T
>::createT
is either the x::ref
or the x::ptr
type.
in this example, button::base
gets typedef-ed to
buttonBase
instead of
x::ptrref_base
, so invoking
button::create
() invokes the custom
create
() method that returns an x::ref
or an x::ptr
,
with
button::base::default_width
and
button::base::default_height
referencing the given
definitions.
In this manner, it's possible to define
custom create
() methods that construct new
pointers or references in arbitrary ways, rather than just by invoking
the corresponding object constructor.
The above example also gives the general naming convention:
for the
reference-counted object itself;
name
Obj
for the
reference to the object, and
name
for the
nullable reference pointer to the object, with the same class typedef-ed
to
name
ptr
and
name
::base
.
name
ptr::base
Sometimes it's convenient to keep the default variadic
create
(), and just supplement
base
with other stuff.
Use the following design pattern to inherit the
the default variadic implementation of
create
() into the base class:
class buttonBase; class buttonObj; typedef x::ref<buttonObj, buttonBase> button; typedef x::ptr<buttonObj, buttonBase> buttonptr; class buttonBase : public x::ptrref_base { public: static const int default_width=50, default_height=50; };
Here, buttonBase
subclasses
x::ptrref_base
, which is the default
base
of an x::ref
or an x::ptr
, and inherits the
default implementation of objfactory
.
For completeness, here's the actual definition of
x::ptrref_base
:
class ptrref_base { public: template<typename ptrrefType> class objfactory { public: template<typename... Args_t> static inline ptrrefType create(Args_t &&...args) { return ptrrefType(new typename ptrrefType ::obj_type(std::forward<Args_t>(args)...)); } }; };
x::ref
and x::ptr
also define the obj_type
member typedef to the reference-counted object type.
() and
x::ref
::create
() forward their arguments to
x::ptr
::createbase::objfactory<
(), where
T
>::createT
is the x::ref
or the x::ptr
type.