Topic: What about a NULL OBJECT?


Author: pascual@gonzo.tid.es (Pascual Juan)
Date: Thu, 11 Mar 1993 17:02:56 GMT
Raw View
What about a NULL OBJECT? It could be the return value in reference functions
when there is nothing to return.

I'm trying to avoid the use of pointers using references instead, but I can't
define a function like:

 Y& X::operator[](int offset){...}

if my offset can go beyond the limits of an instance of X. What to return if
X contents 5 Y's and i ask for the 8th? I know I can do it with pointers
returning NULL in that case:

 Y* X::operator[](int offset){...}

but X will be a container of Y pointers, and I want to work with objects,
not with memory adresses.

So it comes the NULL_OBJECT, who can solve this problem with a few guidelines:

 1.- Declare in your base class a member function IsIdenticTo()
 who returns if this object is exactly the same object that the
 other object passed as reference argument.

 2.- Declare in all your classes a static member called NULL_OBJECT
 of the same type that each class.

 3.- Define NULL_OBJECT for each class.

 4.- When usig reference functions like above, compare the value
 returned with Y::NULL_OBJECT by the IsIdenticTo() function.

Here comes an example:
_______________________________ CODE STARTS HERE ______________________________
#include <iostream.h>

class Base
{
public:
  Base(int parameter1)
  {
    member1=parameter1;
  }
  virtual void f()
  {
    cout << member1 << endl;
  }

  static Base NULL_OBJECT;                              // This is the
  int IsIdenticTo(const Base& other_object) const       // declaration
  {                                                     // of the
    return ( this==&other_object );                     // NULL_OBJECT
  }                                                     // handling

private:
  int member1;
};

Base Base::NULL_OBJECT(0);                              // This is the
                                                        // definition
void main()
{
  Base b1(1);

  Base& tmp=b1;
  if ( ! tmp.IsIdenticTo(Base::NULL_OBJECT) );
  {
    tmp.f();
  }
}
-------------------------------- CODE ENDS HERE -------------------------------

This is a stupid example to show the syntax, but the real power of the
NULL_OBJECT arrives with templates. You can define:

 template <class T>
 T& List<T>::operator[](int n)
 {
   if ( (n>=0) && (n<total) )
   {
     .
     .
     .
     // Returns the n'th element of the list
   }
   else
   {
     return T::NULL_OBJECT;
   }
 }

and use it with each class which follows the last four guidelines:

 void main()
 {
   List<Base> list1;

   Base b1(1);
   Derived d1(2, 3);
   Derived d2(4, 5);

   list1.Insert(b1);
   list1.Insert(d1);
   list1.Insert(d2);

   for ( int i=0;
         i<4;
         i++ )
   {
     Base& tmp=list1[i];
     if ( !tmp.IsIdenticTo(Base::NULL_OBJECT) )
     {
       tmp.f();
     }
   }
 }

where you can use objets instead of pointers in a powerfull way.

In spite of the beauty code, there are some drawbacks in the use of
NULL_OBJECT:

Q: What if you forget the checking betwen the reference and the
 X::NULL_OBJECT?
A: You still can do mistakes, but it will be worse if you attempt to
 call a member function of the object pointed by NULL.

Q: Why the NULL_OBJECT is not a const object?
A: If "Y& X::operator[](int)" can return the const object Y::NULL_OBJECT
 it must be declared as "const Y& X::operator[](int)", so it
 could be used only in read-only-functions. It's no usefull.

Q: How can I avoid modifying the X::NULL_OBJECT?
A: You must not use the contents of any NULL_OBJECT, so you don't
 care if you modify it. But if you want explicity avoid this
 modifications, check at the beggining of every non-const member
 function if you are trying to modify the NULL_OBJECT:
  X& X::operator=(X& x)
  {
    if ( IsIdenticTo(NULL_OBJECT) )
    {
      // handle the exception...
    }
    else
    {
      // do it...
    }
  }
 As IsIdenticTo() is an inline function there is no considerable
 performance penalty.

Q: Ok you win...
A: He, He...      :-)

Maybe I forgot some other drawbak you found. Please post it or mail me
if it is too serious to make me be ashamed to post this article. I will
summarize.

Are you still here? Thak you to be so patient.

      Pascual Juan
      Telefonica I+D
      pascual@tid.es

DISCLAIMER: This are my own opinions, and I'm not responsible of their use.






Author: ort@netcom.com (David Oertel)
Date: Fri, 12 Mar 1993 12:18:52 GMT
Raw View

From: pascual@gonzo.tid.es (Pascual Juan)
>What about a NULL OBJECT? It could be the return value in reference functions
>when there is nothing to return.

>I'm trying to avoid the use of pointers using references instead, but I can't
>define a function like:

> Y& X::operator[](int offset){...}

 Why are you bothering to do this?  The rule is: if an object may not
 exist, then use pointers.  If an object is guaranteed to exist, then
 use references.  There is nothing noble about using references.

 dave oertel
 ort@netcom.com
--