Multiple inheritance and casting

A subclass that inherits from two different reference-counted objects inherits a single x::obj superclass, since it's virtually inherited:

class widgetObj : virtual public x::obj {

// ....

};

class containerObj : virtual public x::obj {

// ....

};

class boxObj : public widgetObj, public containerObj {

// ....
};

typedef x::ref<widgetObj> widget;
typedef x::ref<containerObj> container;
typedef x::ref<boxObj> box;

typedef x::ptr<widgetObj> widgetptr;
typedef x::ptr<containerObj> containerptr;
typedef x::ptr<boxObj> boxptr;

This is the reason why x::obj should always be inherited virtually.

An x::ref or an x::ptr to a subclass may be converted to an x::ref or an x::ptr to its superclass. The opposite is also true: an x::ref or an x::ptr to a superclass may be converted to an x::ref or an x::ptr to a subclass, but only if the referenced object is actually an instance of the subclass, of course:

widget wRef;
container cRef;

// ...

cRef=wRef;

// ...

wRef=cRef;

A runtime exception gets thrown if the pointer or the reference cannot be converted. Use dynamic_cast<> if it's unknown whether the superclass reference refers to an instance of a subclass:

if (!wRef.null())
{
    widgetObj *wptr(&*wRef);

    if (dynamic_cast<boxObj *>(wptr))
    {
       container cRef(wRef);

       // ....
    }
}

Conversion between an x::ref or an x::ptr (source) to a different x::ref or an x::ptr (destination) proceeds as follows. If the destination is a superclass of the source, the conversion uses a static_cast. Otherwise the conversion uses a dynamic_cast and thrown an exception if the conversion fails.

A destination class can avoid the overhead of a dynamic_cast by defining a cast_from() class method that returns a plain pointer to the destination class with a pointer to a plain source class as a parameter:

class aObj : virtual public x::obj {

public:

	virtual D *getd() { return nullptr; }

};

class bObj : public aObj {
};

class dObj : public bObj {

public:

	static dObj *cast_from(aObj *a)
	{
		return a->getd();
	}

	dObj *getd() override { return this; }
};

// ...
x::ref<aObj> return_a();

x::ref<dObj> d=return_a();

Normally an attempt to convert an x::ref of aObj to dObj gets carried out via a dynamic_cast. Here, dObj defines a cast_from static class method that takes a pointer to an aObj and returns a DObj. This results in the dynamic_cast getting replaced by the cast_from() call.

The intended use is to have cast_from invoke a virtual method in the source class. The base implementation in the source class returns a nullptr by default, with the destination class overriding and simply returning this. The end result is a good enough facsimile for a dynamic_cast that it ends up being used as a pinch-hitter.

This design pattern replaces an otherwise expensive dynamic_cast with a much cheaper virtual function dispatch. The functionality of a full dynamic_cast isn't matched identically, but this should suffice for most common use cases.

Restricting overload resolution

Implicit conversion from an x::ref or an x::ptr to a different x::ref or an x::ptr means that a function with an x::ref or an x::ptr parameter participates in overload resolution if the corresponding parameter is any other x::ref or an x::ptr. Sometimes it is desirable to turn off overload resolution. This is done by using an x::explicit_refptr parameter:

#include <x/refptr_traits.H>

typedef x::ref<class1Obj> class1;

typedef x::ref<class2Obj> class2;

void foo(const x::explicit_refptr<class1> &arg)
{
    const class1 &rarg=arg;

    // ...
}

void foo(const x::explicit_refptr<class2> &arg)
{
    const class2 &rarg=arg;

    // ...
}

The first foo() participates in overload resolution only if the corresponding parameter is an x::ref or an x::ptr of a class1Obj, and the second one only for a parameter of an x::ref or an x::ptr of a class2Obj.

An explicit_ref of a x::ref still participates in overload resultion of a x::ptr to the same underlying object. An x::explicit_arg only participates in an overload resolution for the same exact x::ref or an x::ptr:

#include <x/refptr_traits.H>

typedef x::ref<class1Obj> class1;

typedef x::ref<class1Obj> class1ptr;

void foo(const x::explicit_arg<class1> &arg)
{
    const class1 &rarg=arg;

    // ...
}

void foo(const x::explicit_arg<class1ptr> &arg)
{
    if (arg)
    {
        const class2 &rarg=arg;

        // ...
    }
}