Specifying a custom 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<T>::create(), where T 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: nameObj for the reference-counted object itself; name for the reference to the object, and nameptr for the nullable reference pointer to the object, with the same class typedef-ed to name::base and nameptr::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. x::ref::create() and x::ptr::create() forward their arguments to base::objfactory<T>::create(), where T is the x::ref or the x::ptr type.