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
--