A ptr<T> is implemented in terms of a pair of underlying pointers:
Given one or more coercions from Circle to IShape within a given executable or library, the compiler generates a single static vtable of pointers to functions corresponding to the declared methods in the IShape interface. Each function takes a pointer to a Circle object as the first argument (i.e. in addition to the declared formal arguments).
The run time overheads of coercion are minimal - only requiring initialisation of the two pointers within the ptr<IShape>: the address of the circle object and the vtable pointer. This may only require two mov machine code instructions.
The interface IShape defined as follows
$interface IShape
{
float64 GetArea() const;
float64 GetPerim() const;
};
is translated into the following C++ by the Xcpp front end:
struct IShape
{
struct FnTable
{
float64 (*GetArea)(void const* _self);
float64 (*GetPerim)(void const* _self);
};
IShape(void* _self, const FnTable* table) : m_self(_self), m_table(table) {}
void AssignFrom(IShape& _rhs) { m_self = _rhs.m_self; m_table = _rhs.m_table; }
void AssignFrom(IShape const& _rhs) const { const_cast<IShape*>(this)->m_self = _rhs.m_self; const_cast<IShape*>(this)->m_table = _rhs.m_table; }
template<typename T> struct Stubs
{
static float64 GetArea(void const* _self) { return ((const T*)_self)->GetArea(); }
static float64 GetPerim(void const* _self) { return ((const T*)_self)->GetPerim(); }
static const FnTable& GetTable()
{
static const FnTable t =
{
&GetArea,
&GetPerim
};
return t;
}
};
template<typename T> void CoerceFrom(T* _rhs) { m_self = _rhs; m_table = &Stubs<T>::GetTable(); }
template<typename T> void CoerceFrom(const T* _rhs) const { const_cast<IShape*>(this)->m_self = const_cast<T*>(_rhs); const_cast<IShape*>(this)->m_table = &Stubs<T>::GetTable(); }
float64 GetArea() const { return m_table->GetArea(m_self); }
float64 GetPerim() const { return m_table->GetPerim(m_self); }
union
{
void* m_self;
};
FnTable const* m_table;
};