Topic: C++ change: virtual constructors?


Author: nate0001@aol.com (Nate0001)
Date: 1995/04/22
Raw View
Two reactions:

  (1) I've often scratched my head and said, "I wish I had a virtual
constructor here."

  (2) I'm not sure I like potential implications for the linkage between
base class and
      subclass.  Would the base class have to be omniscient about its
possible derived
      classes in order to instantiate them?

  (3) Factories and static "instance" methods seem to me to fill most of
the spaces where
       I would want to use a "virtual constructor".

Do you see this as being an optional kind of constructor, denoted by a
modifier on the
declaration for the constructor, like "virtual" ?  Would all other 'this'
pointers be of  the
normal single-indirection (*) kind, and only the "virtuals" be double (**)
?





Author: cbay@menken.ecte.uswc.uswest.com (Charles Bay)
Date: 1995/04/20
Raw View
Sorry, I was a little sloppy in my posting of the example for
a possible programmer implementation for a virtual constructor.
The correction is below:

...
(Most of the previous posting deleted, please refer to the previous
post if you want to review my senseless patter.)
...

If changed the language to have the compiler generate a **this instead
of a *this, and our memory map was the following:

  **this
----------
| 0xAAAA | >-------\      entity_ptr
----------         |      ----------
                   \----->| 0xBBBB |>----\       Data members
                          ----------     |       ------------
                          | 0xCCCC |     \------>|  int x   |
                          ----------             ------------
                             vptr                |  int y   |
                                                 ------------

                   |                     |                      |
    Pointer or     |    Created when     |     Created when     |
 reference to the  |    my_shape is      |     my_shape is      |
      entity       |  instantiated, is   |   instantiated, is   |
     (default      |the entity's constant|the volatile structure|
compiler-generated |    base point of    |  of manipulation in  |
  **this pointer)  |      reference.     |  the virtual object  |
                   |                     |      polymorph.      |
-----------------------------------------------------------------

The example of a programmer-defined conversion function that would
simulate the behavior of a virtual constructor is the following:

// E x a m p l e ---------------------------------------------------
void Shape::polymorphSelf(ShapeType new_type)
{ // (Assuming ShapeType is an enumeration.)
  Shape* temp;

  // Do a programmer-defined conversion.
  switch(new_type)
  {
    case CIRCLE:
      temp = new Circle();
      temp->x = x;                         // Keep our current x.
      temp->y = y;                         // Keep our current y.
      delete this->entity_ptr;             // Get rid of the old self.
      this->entity_ptr = temp->entity_ptr; // 1. Become the new self.
      this->vptr       = temp->vptr;       // 2. Become the new self.
    case SQUARE:
      ... // Same as circle.
  }
}
//---------------------------------------------------------------
// NOTE:  THIS KEY ABILITY TO ASSIGN A VALUE TO *this, (which is
//   the same as the *entity_ptr presented here), THEREBY
//   CHANGING THE SPECIFICATION/STATE OF THE ENTITY, IS THE
//   FUNDAMENTAL REQUIREMENT FOR OBJECT MORPHING; if we decide
//   we want that kind of thing.
//---------------------------------------------------------------

QUESTIONS FOR DEBATE:
(1) Do you think the language can ever support virtual
constructors without dropping backwards compatibility to its
present version/state?

(2) Do you care?  Do we really need/want virtual constructors?
How bad do you want them?  How much would you use them?

(3) Do you have another option for implementing virtual
constructors?  Consider implementation or behavior, compatibility
to existing code (the existing language) or not.

RESPONSE:
Please get back to me at:

              charley@agrostis.nrel.colostate.edu

and I will summarize and post the responses.

--charley bay                          o o      _--/\___/ /
Daytime (303) 235-3191                     o  ) o |))))) |
cbay@lookout.ecte.uswc.uswest.com              \ /))))) \_\
charley@agrostis.nrel.colostate.edu              \\--\\
..................................................................
I would state these views are mine and not those of my employer,
but I don't have an employer.   :-)







Author: cbay@menken.ecte.uswc.uswest.com (Charles Bay)
Date: 1995/04/18
Raw View
I have created many OO designs with _good_ levels of success.
Every now and then, however, my life would be much easier if I
had a virtual constructor.  I am fully aware of the work-arounds
to simulate behavior of virutual constructors, but language
support would be (a pain to implement, highly controversial) nice.

I expect virtual constructors to directly address the following:

(1) The entity is inherently modified in form and possibly state.

(2) The modification allows pointers and references to the entity
    to still correctly "point at"/"refer to" the entity.

In relation to (2) above, sub-issues arise. If we have virtual
constructors...

? SHOULD an entity only be allowed to "virtually construct" to a
derived class, thus minimizing the possibility of being incorrectly
referenced by an existing pointer to the entity set prior to
"virtual re-construction"?

? SHOULD special procedures be set to allow an entity to be
"virtually re-constructed" to a sibling (or even base) class?

All of these are do-able:  we programmers "are a bunch of strange
folks."  -- Ted Faison, 1993  ;-)

To accomplish objectives (1) and (2) above (ignoring for now the
"SHOULD?" issues raised), I propose code that looks like the
following:

//----------------------------------------------------------------
// D o   T h i s   F o r   V i r t u a l  C o n s t r u c t o r s
class Shape
{
    int x, y;                     // Screen location.
  public:
    virtual Shape(int x, int y);
};

class Circle : public Shape
{
    int radius;
  public:
    virtual Circle(int radius);   // "virtual" is redundant, but
      //   allowed.
};

class Square : public Shape
{
    int side_length;
  public:
    virtual Square();             // "virtual" is redundant, but
      //   allowed.
};

// E x a m p l e ---------------------------------------------------
// Create an instance of the base, and later inherently "polymorph"
//   or modify the entity to a new entity (this example shows the
//   more extreme transformation to a sibling object, although the
//   more simple modification to a derived instance should be the
//   most common application.)

Shape my_shape(4, 20);    // Create and set fixed screen location.
Shape* s_ptr = &my_shape; // A pointer to our one-and-only.

my_shape.Circle(4);       // Become a circle with a radius of 4.
s_ptr->Square();          // Become a square, side length=4.
// E n d -----------------------------------------------------------

Implementation of the above is possible (simple?) if we had a
**this, instead of a *this.  Every object with virtual constructors,
then, would actually be instantiated as a pointer (entity_ptr) to
another "structure" (also instantiated) that contains the object's
data members.  Under this scenario, we could even remove vptr from
the object itself (removing compiler needs for offset calculations)
by putting the vptr with the entity_ptr--the pointer to the actual
structure of data members.  At this point, virtual constructors
will actually modify the "structure" of data members pointed at by
the entity_ptr, and the entity_ptr (and the vptr when necessary)
is the constant item (entity) to which other pointers (references)
may reference.

The memory map is the following:

  **this
----------
| 0xAAAA | >-------\      entity_ptr
----------         |      ----------
                   \----->| 0xBBBB |>----\       Data members
                          ----------     |       ------------
                          | 0xCCCC |     \------>|  int x   |
                          ----------             ------------
                             vptr                |  int y   |
                                                 ------------

                   |                     |                      |
    Pointer or     |    Created when     |     Created when     |
 reference to the  |    my_shape is      |     my_shape is      |
      entity       |  instantiated, is   |   instantiated, is   |
     (default      |the entity's constant|the volatile structure|
compiler-generated |    base point of    |  of manipulation in  |
  **this pointer)  |      reference.     |  the virtual object  |
                   |                     |      polymorph.      |
-----------------------------------------------------------------

Other thoughts:

To get the example to work, the compiler should (by default) perform
a member-wise (bit-wise?) copy from the old to the new.  Child
classes with multiple virtual parents may require a little more
creative manipulation.

If we bite the bullet and go for this (a _suggestion_, not to say
we should blow away backwards compatibility to current use of *this
and re-write all the compilers :-)), programmers could even
implement their own specified entity "polymorph conversion" in a
way like the following:

// E x a m p l e ---------------------------------------------------
void Shape::polymorphSelf(ShapeType new_type)
{ // (Assuming ShapeType is an enumeration.)
  Shape* temp;

  // Do a programmer-defined conversion.
  switch(new_type)
  {
    case CIRCLE:
      temp = new Circle();
      temp->x = x;           // Keep our current x.
      temp->y = y;           // Keep our current y.
      delete *this;          // Get rid of the old self.
      *this = *(temp->this); // Become the new self.
    case SQUARE:
      ... // Same as circle.
  }
}
//---------------------------------------------------------------
// NOTE:  THIS KEY ABILITY TO ASSIGN A VALUE TO (*this), THEREBY
//  CHANGING THE SPECIFICATION/STATE OF THE ENTITY, IS THE
//   FUNDAMENTAL REQUIREMENT FOR OBJECT MORPHING; if we decide
//   we want that kind of thing.
//---------------------------------------------------------------

QUESTIONS FOR DEBATE:
(1) Do you think the language can ever support virtual
constructors without dropping backwards compatibility to its
present version/state?

(2) Do you care?  Do we really need/want virtual constructors?
How bad do you want them?  How much would you use them?

(3) Do you have another option for implementing virtual
constructors?  Consider implementation or behavior, compatibility
to existing code (the existing language) or not.

RESPONSE:
Please get back to me at:

              charley@agrostis.nrel.colostate.edu

and I will summarize and post the responses.  I am not getting
into the newsgroup much lately, so I would appreciate you sending
your flames and comments directly to me.  Don't hold back in your
abuse--I have taught this stuff for six years and heard it all.

Bjarne Stroustrup:  Thanks for the language.  We're having a
blast.

--charley bay                          o o      _--/\___/ /
Daytime (303) 235-3191                     o  ) o |))))) |
cbay@lookout.ecte.uswc.uswest.com              \ /))))) \_\
charley@agrostis.nrel.colostate.edu              \\--\\
..................................................................
I would state these views are mine and not those of my employer,
but I don't have an employer.   :-)