Object Reflection
Keywords: classdesc

Next: Using Classdesc: Method 1, Up: Classdesc Documentation Previous: Contents Contents Index

#
Object Reflection

The basic concept behind this technology is the ability to know rather arbitrary aspects of an object's type at runtime, long after the compiler has thrown that information away. Other object oriented systems (for example Objective C) use dynamic type binding in the form of an `isa` pointer that points to a compiler generated object representing the class of that object. This technology can also referred to as class description, as one only needs to generate a description of the object's class, then ensure the object is bound to that description, hence the name classdesc[8].

In C++, it is not necessary to incur the overhead of an `isa` pointer, as one can bind an object's type to an overloaded instance of a function call at compile time.

A descriptor is a template function `D`

    template <class T>
    void D(D_t&  t, const classdesc::string& d, T& a);

The D t argument allows for state to be maintained while the descriptor is recursively applied to the data structure. If state is not needed for the descriptor, a ``null'' object should be provided for passing through.

Users can specialise the descriptor to handle different types. The classdesc descriptor, however does not specialise the descriptor directly, but rather specialises a functor template:

    template <class T> struct access_D
    {
       void operator()(D_t&, const string&, T&);
    };

There are two advantages of using functional classes:

1. Partial specialisation is available for template classes, but not template functions
2. It is simpler to specify friend access to a functional class for those descriptors needing to access private or protected members(see §1.6)

The generic descriptor then calls `operator()` of the appropriate access class, eg:

    template <class T>
    void pack(classdesc::pack_t& t, const classdesc::string& d, T& a)
    {classdesc::access_pack<T>()(t,d,a);}

but may optionally perform some additional pre/post-processing if sensible for the particular descriptor.

The `classdesc` package comes with several descriptors already implemented:

pack/unpack
  , which implements serialisation
xml_pack/xml_unpack
  , which serialises to/from an XML description of the object.
json_pack/json_unpack
  , which serialises to/from a JSON description of the object.
dump
  , which writes an ascii representation of the object to a `std::ostream` object
javaClass
  , which generates a Java interface to C++ objects using JNI.

`pack` will be documented in more detail later, but a simple overview is that the `pack_t` object is a simple reference to some binary data:

    struct pack_t
    {
      char *data();
      const char *data() const;
      size_t size();
    } buf;

A call to `pack(buf,""",foo)` pushes a binary representation of the object `foo` (regardless of its type) into buf. The inverse operation is called `unpack`. Syntactically, we may also use the `<<` operator for the same purpose:

    buf << foo << bar;
    fwrite(buf.data(),buf.size(),1,f);
    pack_t b1(buf.size());
    fread(b1.data(),b1.size(),1,f);
    b1 >> foo1 >> bar1;

This code has made a copy of `foo` and `bar`, but with the data going via a disk file.

Subsections

- Using Classdesc: Method 1, inlining
- Using Classdesc: Method 2, building a library
- Synopsis of classdesc
- Limitations to classdesc
- supported #pragmas
- CLASSDESC_ACCESS
- Excluding particular members from the descriptor

Next: Using Classdesc: Method 1, Up: Classdesc Documentation Previous: Contents Contents Index