An object can be queried for particular interface (see upf::IObject::queryInterface). The object returns interface identification if it implements it or informs the caller that given interface is not supported by this class.
For example, you may have interface IFoo and IBar and classes A, B and C, where A implements interface IFoo, B implements IBar and C implements both interfaces. You can access both A and C via IFoo API (interface).
Interfaces in UPF are versioned. Every interface has two version numbers associated with it: major and minor. Any two interfaces with different major version numbers are incompatible (i.e. a module that knows one version of the interface cannot interoperate with another one which implements different version).
If major numbers are same and two interfaces only differ in minor version, then the situation is different: the class that implements interface with higher minor version is assumed to implement all lower minor versions of the interface. If, for example, A implements version 1.2 of an interface and B implements version 1.1, then B can safely access A (because it is compatible with 1.2, 1.1 and 1.0), but A cannot use with B (because A only knows version 1.2 of the interface whereas B can only provide versions 1.1 or 1.0).
Version is specified using #pragma version (interface) (major).(minor) declaration in IDL file. If the pragma is omitted, version 1.0 is assumed. Here is an example:
interface Foo : upf::IObject { ... }; #pragma version Foo 2.3
Reference counting is mostly hidden from the programmer by language-specific constructs. In C++, for example, the programmer should use upf::Ptr template class.
It is important to be aware of UPF's use of reference counting because sometimes circular references may occur and if you don't handle such situations in your code, the app would leak memory.
Some properties have meanings associated with them by convention, though:
1.3.9.1