Difference between revisions of "Overriding Constructors"

From MorphOS Library

(Contents.)
Line 26: Line 26:
  
 
The only question remaining is what ''CoerceMethod()'' does and why it is used instead of a plain ''DoMethod()''? The ''CoerceMethod()'' call works exactly the same as ''DoMethod()'', but performs '''method coercion''' by forced call to the dispatcher of the class specified as the first argument instead of the dispatcher of the object's true class. It makes a difference, when the class in question is later subclassed. The flowchart below explains the problem:
 
The only question remaining is what ''CoerceMethod()'' does and why it is used instead of a plain ''DoMethod()''? The ''CoerceMethod()'' call works exactly the same as ''DoMethod()'', but performs '''method coercion''' by forced call to the dispatcher of the class specified as the first argument instead of the dispatcher of the object's true class. It makes a difference, when the class in question is later subclassed. The flowchart below explains the problem:
 +
 +
 +
[[File:Coercemethod.png|center]]
 +
 +
 +
The class ''B'' on the diargam is a subclass of the class ''A'' and similarly, the class ''C'' is a subclass of ''B''. Let's assume an object of the class ''C'' is being constructed. As every constructor calls the superclass first, the call goes to ''rootclass'' (the root of all BOOPSI classes) first. Then going down the class tree, every class constructor allocates its resources. Unfortunately the constructor of class ''A'' has been unable to allocate one of resources and decided to fail.

Revision as of 13:41, 4 January 2011

Grzegorz Kraszewski


An object constructor (OM_NEW() method), takes the same message structure opSet as OM_SET() method. The message contains ops_AttrList field, being a pointer to a taglist containing initial object's attributes. Implementation of a constructor for an object not chaving child objects is simple. The superclass constructor is called first, then, if it succeeds, the constuructor initializes object instance data, allocates resources needed and sets initial values of attributes from tags passed via ops_AttrList.

A rule of thumb when overriding constructor is to never leave a half-constructed object. The counstructor should either return a fully constructed object, or fail completely, freeing all succesfully obtained resources. It is important if the object obtains more than one resource and any of resource allocation may fail (for example allocating a big chunk of memory or opening a file). An example implementation below obtains three resources: A, B and C:

IPTR MyClassNew(Class *cl, Object *obj, struct opSet *msg)
{  
  if (obj = DoSuperMethodA(cl, obj, (Msg)msg))
  {
    struct MyClassData *d = (struct MyClassData*)INST_DATA(cl, obj);

    if ((d->ResourceA = ObtainResourceA()
     && (d->ResourceB = ObtainResourceB()
     && (d->ResourceC = ObtainResourceC())
    {
      return (IPTR)obj;    /* success */
    }
    else CoerceMethod(cl, obj, OM_DISPOSE);
  }
  return NULL;
}

If the object destructor frees resources A, B and C (which would be logical considering the constructor allocates them), the cleanup job may be delegated to the destructor. It requires however, that the destructor must be prepared for destruction of not fully constructed object. It can't assume all three resources have been allocated, so it should check every resource pointer against NULL before calling a freeing function. The desctructor also takes care of calling a superclass destructor when resources are freed. See Overloading Destructors for a destructor example code and explanation.

The only question remaining is what CoerceMethod() does and why it is used instead of a plain DoMethod()? The CoerceMethod() call works exactly the same as DoMethod(), but performs method coercion by forced call to the dispatcher of the class specified as the first argument instead of the dispatcher of the object's true class. It makes a difference, when the class in question is later subclassed. The flowchart below explains the problem:


Coercemethod.png


The class B on the diargam is a subclass of the class A and similarly, the class C is a subclass of B. Let's assume an object of the class C is being constructed. As every constructor calls the superclass first, the call goes to rootclass (the root of all BOOPSI classes) first. Then going down the class tree, every class constructor allocates its resources. Unfortunately the constructor of class A has been unable to allocate one of resources and decided to fail.