Chapter 5. VOS Programming

Code tutorials for writing applications and MetaObject implementations using the VOS C++ library

5.1. VOS in C++

5.1.1. C++ Tutorials

A complete introduction to the VOS API is given through the following seven tutorials. In the VOS distribution these tutorials may be found in vos/apps/tutorials along with the appropriate files for compiling them.

  1. The simplest possible program that uses VOS.

  2. Introduction to Vobjects.

  3. Local and Remote Vobjects and Messages.

  4. Linking Vobjects together.

  5. Introduction to Metaobjects.

  6. Child and Property Listeners

  7. Creating your own MetaObjects

5.1.2. Common Coding Questions

Q: What's the deal with this vRef stuff?
Q: What's the deal with meta_cast?

Q: What's the deal with this vRef stuff?

A: VOS uses a reference-counted memory management scheme. This means that each reference-counted object (implemented by subclassing "RefCounted" in the C++ library) has a "count" associated with it. This count is the number of times that this object is pointed ("referred") to somewhere in the running program. When a new reference is created (the refcounted object is "acquired") the reference count is incremented. When the a reference is destroyed (the refcounted object is "released") the count is decremented. When the reference count drops to zero, the object can be safely deallocated because we know there are no references to it left in the program.

The purpose of vRef is help you use with VOS's reference counting with a minimum amout of fuss. The vRef template is what is known as a "smart pointer". It is a small class which holds the reference to some object and automatically releases that reference when the vRef class is destroyed. It frees you from most of the hassle of dealing with memory management (at least as far as vobjects and related classes are concerned.) You should always use vRef whenever you get a RefCounted object from VOS.

Keep in mind that vRef automatically releases the object, but it does not acquire an object that you assign to it: if you want to store a reference to an object beyond the scope of its current vRef, acquire it (call acquire()) when you assign the pointer or vRef in which you will be storing it.

You may notice that some code uses certain macros rREF and pREF. These perform a very similar function to the vRef smart pointer (automatically releases a reference when it is no longer accessable), but suffered from a few problems and are now deprecated in favor of vRef. For details about rREF and pREF please consult the API documentation. New code should just use vRef, and old code is slowly being converted.

Q: What's the deal with meta_cast?

A: Being polymorphic, Vobjects may implement many different interfaces. The mechanism to select between these interfaces is meta_cast(). This method is intended to appear similar to other C++ typecasting functions (dynamic_cast, reinterpert_cast, static_cast) so it should be comfortable if you are familiar with C++ casts. Using meta_cast is simple: you give it a Vobject and a desired interface class, and you get back a reference or pointer of the appropriate class. If the Vobject does not support the desired class, then it will throw a bad_cast exception (if you did a cast or a reference) or return NULL (if you did a cast on a pointer.) An example:


try {
    vRef<Vobject> myobject = findObject("foo");
    FunkyInterface& fi = MetaObject::meta_cast<FunkyInterface&>(myobject);
    fi.funkyMethod();
} catch(bad_cast) {
    LOG("myprogram", 2, "foo is not a FunkyInterface!");
} catch(Vobject::NoSuchObjectError) {
    LOG("myprogram", 2, "foo does not exist");
}
		  

One important detail is that meta_cast does NOT increment the reference count, so its result doesn't neccesarily need to be stored in a vRef.

This dynamic polymorphism is implemented using the MetaObject extensions discussed earlier. Each interface is usually a different actual C++ object. Behind the scenes these objects are rigged up to seamlessly act as the same logical Vobject. Internally, meta_cast works by going through each metaobject extension attached to the object and performing a C++ dynamic_cast to test for support for the desired interface; the first object which does support the interface is returned to the user.

5.1.3. Common VOS Programming Errors

As an aid to prevent redundant frustration, here is a list of common VOS programming errors. If you have encountered an annoying error that you think might plague others (especially newbies), please send it in to reed@interreality.org or post it to the discussion list.

5.1.3.1. Access control

All objects must have access control, and all properties must have property access control. Many MetaObject classes which manage subproperties have a method called setPropertyAccessControl() or initialize() which allows you to set a default property access control policy for all of that object's subproperties. Make sure you call that method immediately after creating the object. You can use &NoAccessControl::static_ to get a pointer to a permissive static AC policy object. (There is also an analogous &NoPropertyAccessControl::static_). Beware! These policies allow anyone to do anything to the Vobject or propery!

5.1.3.2. Uninitialized subproperties

Many MetaObjects (e.g. A3DL) have required subproperties. Applications will assume these properties exist. Make sure you set those subproperties immediately after creating the object. Some MetaObjects have an initialize() method which will set all non-optional subproperties to default values. Applications should catch the exception Vobject::NoSuchObjectError when attempting to access optional subproperties.

5.1.3.3. Register MetaObjects!

Don't forget to register the MetaObjects you are going to use, by calling its registerExtenders() method. If a MetaObject type has not been registered, Site::createMetaObject() will return a NULL pointer. You can register all the A3DL types by calling A3DL::registerAll(). It's a good idea to always call Property::registerExtenders(), as almost all other MetaObjects use Property.

5.1.3.4. Duplicate site links

An object can be a child of only one, local site, and cannot be the child of that or any other site under any name. In other words, this is illegal:


MetaObject* c = site.createMetaObject( "foo", ... );
site.insertChild(-1, "bar", c);
        

5.1.4. C++ API Reference

The latest API documentation can be found locally here or online at http://interreality.org/docs/