Reference Types

About

Interfaces in the MAXON API can be "virtual" or "non-virtual" interfaces. Such interfaces can be registered using different reference types. These reference types define how the created reference classes are build and how they behave.

Note
"Virtual" interfaces should be preferred.

Interface Reference Types

These reference types are applicable to virtual and non-virtual interfaces:

Note
Virtual interface instances always use reference counting.

CONST

An interface using MAXON_REFERENCE_CONST only adds const functions to the created reference class. To create instances of such a read-only object a helper interface might be used that is able to create different objects (see also Factories).

The declaration of the const interface and the helper interface could look like this:

// This example shows an interface which uses MAXON_REFERENCE_CONST
// so only const functions are added to the reference class.
// ---------------------------------------------------------------------
// A custom unique ID class.
// ---------------------------------------------------------------------
class CustomUniqueIdInterface : MAXON_INTERFACE_BASES(maxon::ObjectInterface)
{
MAXON_INTERFACE(CustomUniqueIdInterface, MAXON_REFERENCE_CONST, "net.maxonexample.interfaces.uniqueid");
public:
// ---------------------------------------------------------------------
// Returns the internal unique ID.
// ---------------------------------------------------------------------
MAXON_METHOD maxon::UInt GetId() const;
};
// forward declaration of the reference class
// const classes do not use the suffix "Ref"
class CustomUniqueId;
// ---------------------------------------------------------------------
// Non-virtual interface as a CustomUniqueId generator.
// ---------------------------------------------------------------------
class CustomUniqueIdGenerator
{
MAXON_INTERFACE_NONVIRTUAL(CustomUniqueIdGenerator, MAXON_REFERENCE_NONE, "net.maxonexample.interfaces.uniqueidgenerator");
public:
// ---------------------------------------------------------------------
// Returns a new CustomUniqueId or an error.
// ---------------------------------------------------------------------
};
Definition: resultbase.h:766
UInt64 UInt
unsigned 32/64 bit int, size depends on the platform
Definition: apibase.h:191
#define MAXON_INTERFACE_NONVIRTUAL(Name, REFKIND, ID)
Definition: interfacebase.h:1302
#define MAXON_REFERENCE_CONST(FREEIMPL)
Definition: interfacebase.h:1159
#define MAXON_REFERENCE_NONE(FREEIMPL)
Definition: interfacebase.h:1018
#define MAXON_INTERFACE(Name, REFKIND, ID)
Definition: objectbase.h:1125
#define MAXON_METHOD
Definition: interfacebase.h:942
#define MAXON_INTERFACE_BASES(...)
Definition: objectbase.h:1054

The implementation of the const class can look like this. Notice the Init() function that takes an argument:

// This example shows an implementation of a const interface.
// The only way to modify the internally stored data is on creation with Init().
// implementation of CustomUniqueIdInterface
class UniqueIdImp : public maxon::Component<UniqueIdImp, CustomUniqueIdInterface>
{
public:
{
_id = id;
return maxon::OK;
}
MAXON_METHOD maxon::UInt GetId() const { return _id; }
private:
};
Definition: objectbase.h:2632
Definition: resultbase.h:193
return OK
Definition: apibase.h:2620
#define MAXON_COMPONENT(KIND,...)
Definition: objectbase.h:2193

The implementation of the helper interface creates a new object by creating a new instance of the component. Calling CreateInit() will invoke the above Init() function.

// This example shows the implementation of a static non-virtual interface function.
// This function can access an implementation class (UniqueIdImp) to create a new instance.
maxon::Result<CustomUniqueId> UniqueIdGeneratorImpl::GetUniqueID()
{
// increment global ID
g_uniqueIDs++;
// create new UniqueId
return UniqueIdImp::CreateInit(g_uniqueIDs);
}

Now one can use the helper interface to create a new instance of the read-only const interface.

// This example creates a new CustomUniqueId object using a static function of a helper interface.
// create ID
const CustomUniqueId id = CustomUniqueIdGenerator::GetUniqueID() iferr_return;
// use ID
const maxon::UInt value = id.GetId();
DiagnosticOutput("UID: @", value);
maxon::UInt UInt
Definition: ge_sys_math.h:65
#define DiagnosticOutput(formatString,...)
Definition: debugdiagnostics.h:176
The maxon namespace contains all declarations of the MAXON API.
Definition: c4d_basedocument.h:16
#define iferr_return
Definition: resultbase.h:1465

COPY_ON_WRITE

If an object of a copy-on-write class is copied, it will not copy its content. It will only store a reference to the original object. Only if the copy or original object are changed, data is copied.

A simple copy-on-write interface can look like this:

// This example shows a simple interface of the reference type MAXON_REFERENCE_COPY_ON_WRITE.
// ---------------------------------------------------------------------
// Class to store an array of maxon::Float values.
// ---------------------------------------------------------------------
class FloatArrayInterface : MAXON_INTERFACE_BASES(maxon::ObjectInterface)
{
MAXON_INTERFACE(FloatArrayInterface, MAXON_REFERENCE_COPY_ON_WRITE, "net.maxonexample.interfaces.floatarray");
public:
// ---------------------------------------------------------------------
// Adds the given value to the array.
// ---------------------------------------------------------------------
};
Float64 Float
Definition: apibase.h:199
#define MAXON_REFERENCE_COPY_ON_WRITE(FREEIMPL)
Definition: interfacebase.h:1176

The implementation is straightforward:

// This example shows an implementation of a copy-on-write interface.
// implementation of FloatArrayInterface
class FloatArrayImpl : public maxon::Component<FloatArrayImpl, FloatArrayInterface>
{
public:
// implementation of an interface function
{
return _data.Append(value);
}
// implementation of maxon::ComponentRoot::CopyFrom()
maxon::Result<void> CopyFrom(const FloatArrayImpl& arr)
{
return _data.CopyFrom(arr._data);
}
// implementation of maxon::ObjectInterface::ToString()
{
maxon::String result { "Values: " };
for (const maxon::Float v : _data)
result += maxon::String::FloatToString(v) + ", "_s;
return result;
}
private:
};
maxon::String ToString(const Filename &val, const maxon::FormatStatement *formatStatement, maxon::Bool checkDatatype=false)
Definition: basearray.h:413
Class to store formatting statements.
Definition: string.h:2012
Definition: string.h:1226

The reference class of a copy-on-write interface does not use the usual "Ref" suffix. It can be used as usual:

// This example creates and uses copy-on-write objects.
// create original
FloatArray original = componentClass.Create() iferr_return;
// use original
original.AddValue(1.0) iferr_return;
original.AddValue(2.0) iferr_return;
// create copy
FloatArray copy = componentClass.Create() iferr_return;
// data is assigned but not yet copied
copy = original;
// original and copy have access to the same data
DiagnosticOutput("Original: @", original);
DiagnosticOutput("Copy: @", copy);
// add further data; internal data will now be copied
copy.AddValue(3.0) iferr_return;
// original and copy now access different data
DiagnosticOutput("Original: @", original);
DiagnosticOutput("Copy: @", copy);

Non-Virtual Interface Reference Types

These reference types are only applicable to non-virtual interfaces:

NONE

Non-virtual interfaces can use the reference type MAXON_REFERENCE_NONE. This will create a static reference class.

The non-virtual interface is declared like this:

// This example shows a simple non-virtual interface of the reference type MAXON_REFERENCE_NONE.
// ---------------------------------------------------------------------
// Class to roll a dice.
// ---------------------------------------------------------------------
class DiceInterface
{
MAXON_INTERFACE_NONVIRTUAL(DiceInterface, MAXON_REFERENCE_NONE, "net.maxonexample.interfaces.dice");
public:
// ---------------------------------------------------------------------
// Rolls the dice and returns a random number.
// ---------------------------------------------------------------------
static MAXON_METHOD maxon::UInt RollDice();
};

The implementation can look like this:

// This example shows the implementation of a simple interface.
// implementation of DiceInterface
class DiceInterfaceImpl : protected DiceInterface
{
MAXON_IMPLEMENTATION(DiceInterfaceImpl)
public:
static maxon::UInt RollDice();
};
// implementation of DiceInterface::RollDice()
maxon::UInt DiceInterfaceImpl::RollDice()
{
// chosen by fair dice roll.
// guaranteed to be random.
return 4;
}
MAXON_IMPLEMENTATION_REGISTER(DiceInterfaceImpl);
#define MAXON_IMPLEMENTATION(C)
Definition: interfacebase.h:1432
#define MAXON_IMPLEMENTATION_REGISTER(C,...)
Definition: interfacebase.h:1536

The static reference class is used this way:

// This example uses the static member function of the interface.
const maxon::UInt randomNumber = DiceInterface::RollDice();
DiagnosticOutput("Number: @", randomNumber);

Further Reading