🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

1 total messages Started by Jim ADCOCK Wed, 19 Sep 1990 19:41
Re: reference classes, and operator.()
#519
Author: Jim ADCOCK
Date: Wed, 19 Sep 1990 19:41
164 lines
6021 bytes
In article <8445@jarthur.Claremont.EDU> dfoster@jarthur.Claremont.EDU (Derek R. Foster) writes:

|Is there any way to change the variable referenced by a reference variable
|after the reference variable has been initialized?
|
|In particular, I have a class which is passed a reference to a target
|variable which it is to modify. I would like to be able to simply
|declare a class member variable which would be a reference to the
|target variable, thus allowing my class member operations to access
|the target variable as if it was simply a member variable. In other words,
|I would like to be able to 'forget' that the target variable is actually
|external to the particular class object which has been told to modify it,
|except for in the routines which change to a new target. This seems like
|a perfectly legitimate use of a reference variable, and would work quite
|nicely if I was able to specify the target variable at the time a class
|object was constructed. Unfortunately, I can't.....

/****

In valid C++, references cannot be changed after being initialized.  Compilers
can perform significant optimizations on references, due to the fact that 
references cannot be aliased [they have no address, they can alias what they
refer to, but cannot be themselves aliased]  So, its not "legitimate" to try
to "reassign" references via hackery.  However, one can construct one's own
reference class, that internally uses a pointer to store the reference, but
presents that pointer to the outside world as if a reference.   Then you
just create an access member function to allow the internal pointer to be
reassigned to refer to a new object.  Unfortunately, when you try to do this,
you'll find that while C++ allows pointer classes to overload operator->(),
C++ ***does not*** allow reference classes the equivalent option of overloading 
operator.()  To get around this problem, one is forced to provide a forwarding
definition for all the public members of the class being referenced.  This,
in turn, generally prevents reference classes from being implemented via macros
or templates.

-- Please join me in lobbying the ANSI C++ committee to correct this oversight
in the language definition.  Overloading operator.() makes equal sense for
reference classes as overloading operator->() for pointer classes.  Classes
that naturally follow value semantics need to be implementable using 
reference syntax, not pointer syntax, otherwise the usage becomes 
horrible, as you point out. --

The code below illustrates this problem, and the painful work-around.

****/

extern "C" 
{ 
    #include <stdio.h> 
}

class THING
{
    char* name;
public:
    THING(char* nameT) : name(nameT) {}
    void DoSomething() { printf("%s DoSomething()\n", name); }
    void DoSomething2() { printf("%s DoSomething2()\n", name); }
};

typedef THING* PTHING;
typedef THING& RTHING;

// To make the below classes generally useful, you'd probably want to 
// implement them as templates or macros, so that they can be parameterized
// on the type of object being referred to....

// Yes! it's "trivial" to make a pointer class....

class THING_PTR
{
    PTHING pthing;
public:
    THING_PTR() { pthing = 0; }
    THING_PTR(RTHING rthing) { pthing = &rthing; }

    // ....because operator->() ***is*** overloadable.

    PTHING operator->() { return pthing; }

    RTHING operator*() { return *pthing; }
    operator PTHING() { return pthing; }
    void NowReferences(RTHING rthing) { pthing = &rthing; }
    // ....
};

// But, is it trivial to make a reference class? ....

class THING_REF
{
    PTHING pthing;
public:
    THING_REF() { pthing = 0; }
    THING_REF(RTHING rthingT) { pthing = &rthingT; }

    // ....but nooo, because operator.() ***isn't*** overloadable!

    // RTHING operator.() { return *pthing; }

    operator RTHING() { return *pthing; }
    void NowReferences(RTHING rthingT) { pthing = &rthingT; }
    // ....
};

// So, to make a legitimate reference class one has to write a forwarding method
// for every method in the referenced class -- which in turn means the 
// referencing class can't be implemented using macros or templates! 

class PAINFUL_THING_REF
{
    PTHING pthing;
public:
    PAINFUL_THING_REF() { pthing = 0; }
    PAINFUL_THING_REF(RTHING rthingT) { pthing = &rthingT; }

    operator RTHING() { return *pthing; }
    void NowReferences(RTHING rthingT) { pthing = &rthingT; }
    // ....

    // Now, add a forwarding call definition for ***ALL*** of THING's methods
    // ....In this case, just two, thank god....

    void DoSomething() { pthing->DoSomething(); }
    void DoSomething2() { pthing->DoSomething2(); }
};


main()
{
    THING thing1("thing1");
    THING thing2("thing2");

    thing1.DoSomething();
    thing2.DoSomething();  
    putchar('\n');

    THING_PTR thingPtr(thing1);
    thingPtr->DoSomething();
    thingPtr.NowReferences(thing2);
    thingPtr->DoSomething(); 
    putchar('\n');

// Too bad, **someone** decided you can't overload operator, so you
// can't do this: 

    printf("Sorry: THING_REF doesn't work....\n");
    printf("       ....because operator.() isn't implemented yet!\n\n");
#if 0
    THING_REF thingRef(thing1);
    thingRef.DoSomething();
    thingRef.NowReferences(thing2);
    thingRef.DoSomething(); 
    putchar('\n');
#endif

//  -- Except, via the painful class implementation: 

    PAINFUL_THING_REF thingRef(thing1);
    thingRef.DoSomething();
    thingRef.NowReferences(thing2);
    thingRef.DoSomething(); 
    putchar('\n');
}
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads