Interface Implementation

About

An interface declares an empty virtual class. The actual functionality must be defined in an implementation. For a given interface multiple implementations can exist. Such an implementation is called a component.

An implementation can be defined in any source code file of a module/plugin. This way it is possible to publish the interface header file and to keep the implementation private.

Implementation

A simple interface is defined as:

// This example shows the declaration of a simple interface.
// ---------------------------------------------------------------------
// Simple class that stores a maxon::Int number.
// ---------------------------------------------------------------------
class SimpleClassInterface : MAXON_INTERFACE_BASES(maxon::ObjectInterface)
{
MAXON_INTERFACE(SimpleClassInterface, MAXON_REFERENCE_NORMAL, "net.maxonexample.interfaces.simpleclass");
public:
// ---------------------------------------------------------------------
// Sets the number to store.
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Returns the stored number.
// ---------------------------------------------------------------------
};
// This interface is declared in a file named "simpleclass.h". The automatically
// generated files are therefore named "simpleclass1.hxx" and "simpleclass2.hxx"
// The .hxx header files define the reference class "SimpleClassRef".
#include "simpleclass1.hxx"
// declare the published objects "SomeSimpleClass" and "OtherSimpleClass"
// that give access to implementations of SimpleClassInterface
// the declaration must be placed between the two hxx files since "SimpleClassRef" is defined in the first hxx file
MAXON_DECLARATION(maxon::Class<SimpleClassRef>, SomeSimpleClass, "net.maxonexample.somesimpleclass");
MAXON_DECLARATION(SimpleClassRef, OtherSimpleClass, "net.maxonexample.othersimpleclass");
#include "simpleclass2.hxx"
[interfaces_basic_virtual_interface]
Definition: simpleclass.h:15
MAXON_METHOD void SetNumber(maxon::Int number)
MAXON_INTERFACE(SimpleClassInterface, MAXON_REFERENCE_NORMAL, "net.maxonexample.interfaces.simpleclass")
MAXON_METHOD maxon::Int GetNumber() const
Definition: objectbase.h:696
Int64 Int
signed 32/64 bit int, size depends on the platform
Definition: apibase.h:202
#define MAXON_REFERENCE_NORMAL(FREEIMPL)
Definition: interfacebase.h:1184
#define MAXON_DECLARATION(T, Name, id,...)
Definition: module.h:937
#define MAXON_METHOD
Definition: interfacebase.h:1012
#define MAXON_INTERFACE_BASES(...)
Definition: objectbase.h:1049

A simple implementation of that interface can look like this:

// This example shows the implementation of a simple interface.
// This class implements SimpleClassInterface.
class SimpleClassImplementation : public maxon::Component<SimpleClassImplementation, SimpleClassInterface>
{
public:
// implementation of interface methods
MAXON_METHOD void SetNumber(maxon::Int number)
{
_value = number;
}
MAXON_METHOD maxon::Int GetNumber() const
{
return _value;
}
// private data only available inside the implementation
private:
maxon::Int _value = 1;
};
Definition: objectbase.h:2655
#define MAXON_COMPONENT(KIND,...)
Definition: objectbase.h:2212
  • The attribute maxon::Component defines the interface this component implements. A component can also use code defined in a base component. See Component Bases for more details.
  • The attribute MAXON_COMPONENT() declares the class as a component and adds additional code if needed.
  • The component implements the virtual functions of the interface that are declared with MAXON_METHOD.
  • Class members can only exist in the implementation class.

Register

A new component must be registered to inform Cinema 4D about it. The registration defines the ID which can be used to access the component class which in return can be used to create instances. The ID is created by combining the reverse domain name and the implementation class name.

Note
If it should be possible that another interface inherits from a custom interface it is needed that one or many implementations of that interface are accessible (e.g. as published object using MAXON_COMPONENT_CLASS_REGISTER). See Interface Inheritance.
// This example registers the component using the base identifier
// and the implementation class name.
MAXON_COMPONENT_CLASS_REGISTER(SimpleClassImplementation, "net.maxonexample.class.somesimpleclass");
#define MAXON_COMPONENT_CLASS_REGISTER(C,...)
Definition: objectbase.h:2410

It is also possible to expose a given component as a published object that was declared with MAXON_DECLARATION:

// This example registers the component and publishes it as the published object "SomeSimpleClass".
// The published object must be declared in a header file.
MAXON_COMPONENT_CLASS_REGISTER(OtherClassImplementation, SomeSimpleClass);

This published object is used like this:

// This example creates a reference class from a component
// registered at the given declaration.
// create reference
// The "SomeSimpleClass" published object is declared in a header file.
// The obtained component is used to create a new instance using Create().
const SimpleClassRef simpleClass = SomeSimpleClass().Create() iferr_return;
// use reference
simpleClass.SetNumber(456);
const maxon::Int number = simpleClass.GetNumber();
DiagnosticOutput("Number: @", number);
#define DiagnosticOutput(formatString,...)
Definition: debugdiagnostics.h:170
#define iferr_return
Definition: resultbase.h:1524

MAXON_COMPONENT_OBJECT_REGISTER is used to create an instance of the component class and to publish that object:

// This example registers the given implementation, creates an instance of the class
// and makes that object available with the given published object "OtherSimpleClass".
MAXON_COMPONENT_OBJECT_REGISTER(ThirdSimpleClassImplementation, OtherSimpleClass);
#define MAXON_COMPONENT_OBJECT_REGISTER(C,...)
Definition: objectbase.h:2473

The object published this way can be obtained like this:

// This example shows how to access an object created
// and registered with MAXON_COMPONENT_OBJECT_REGISTER.
{
// access object crated with MAXON_COMPONENT_OBJECT_REGISTER
const SimpleClassRef& simpleClass = OtherSimpleClass();
const maxon::Int number = simpleClass.GetNumber();
DiagnosticOutput("Number: @", number);
}
{
// create copy of the object created with MAXON_COMPONENT_OBJECT_REGISTER
const SimpleClassRef simpleClass = OtherSimpleClass();
// use reference
simpleClass.SetNumber(789);
const maxon::Int number = simpleClass.GetNumber();
DiagnosticOutput("Number: @", number);
}
#define MAXON_SCOPE
Definition: apibase.h:2886

Multiple Components

The attribute MAXON_COMPONENT() declares a given class as a component. The attribute can be used to define the component type:

Additionally, MAXON_COMPONENT() can define additional components that are added to a given component. If this is not sufficient one can implement maxon::ComponentRoot::ConfigureClass(). These additional components typically implement the interface's base interfaces. See Interface Inheritance.

Default Functions

Every component can implement these default functions. They are declared in the maxon::ComponentRoot class.

  • maxon::ComponentRoot::InitImplementation(): Is called when the component is loaded (Cinema 4D startup).
  • maxon::ComponentRoot::FreeImplementation(): Is called when the component is unloaded (Cinema 4D shutdown).
  • maxon::ComponentRoot::InitComponent(): Is called when an instance of the component is created.
  • maxon::ComponentRoot::FreeComponent(): Is called when an instance of the component is destroyed.
  • maxon::ComponentRoot::CopyFrom(): Is needed if a component has data members and to support maxon::ObjectInterface::CopyFrom() and maxon::ObjectInterface::Clone().
  • maxon::ComponentRoot::DescribeIO(): Is needed to describe how data members must be written to disc. See DescribeIO Manual.
  • maxon::ComponentRoot::ConfigureClass(): Is called to add additional components.
Note
InitImplementation() is called before the Cinema 4D core is loaded. This means that no classic API code can be called in this context.

Static Methods

Static methods of interfaces can only be implemented once. The implementation class of these methods must be additionally registered with MAXON_STATIC_REGISTER().

Further Reading