From: pf@bilbo.bio.purdue.edu (Paul Furbacher)
Subject: Re: Questions about Constructors and pointers to objects in TP 6
Followup-To: comp.lang.pascal
Organization: Purdue University
Date: Sat, 23 Jan 1993 07:34:59 GMT

Where do we start and how can we be gentle with the following?

In article <1993Jan22.171839.4925@cs.wm.edu>, 
  greg@ms.cs.wm.edu (Gregory S. Miller) wrote:
> 
> Is it legal for the constructor for an object to call the 
> constructor for a parent object?

As they say on TV (the tube, not the framework), "Read the book."
Essentially, it says, yes.  If you have any of the source code 
which comes with TP6.0 or BP7.0, read that also.  You'll see 
many examples of this.  Precisely, this is what inheritance is
all about, choosing to talk to your parents or not.  If you choose
to converse with the ancestors, the question becomes *when*.

> I am having some difficulty with virtual method calls going to the wrong
> class method, and was wondering if I might be accidentally overwriting
> the pointer to the VMT by calling the parent class constructor from within 
> the descendant class constructor.
> 
> A pointer of type pClass is assignment-compatible with ALL descendants of
> Class, correct?

Correct, with the appropriate typecasting.  But you can get
into trouble with this.  By typecasting, you're trying
to fake out the type-checking mechanisms built into the compiler,
and type-checking is one of the reasons you program in Pascal 
and not something like C or BASIC.

> As a result, the following should work:
> 
> 	New(pDescendantPtr,Init(Stuff));
       ^          ^^^
                  redundant: the "P" at the beginning means "ptr"!

   You've got to sit down with your manual, read it and, I'm sorry to
say, comprehend it.  After that try the following:

   MyDescendent := New(PDescendent, Init(...)); {ellipsis, not "Stuff"}

> 	pClassPtr := pDescendantPtr;

No, no, no.  Assuming you are following naming conventions (it's
apparent that you are not) you are trying to assign types and 
not variables.  Again, look at the redundancy in your naming. 
(To re-iterate and paraphrase what S.A. Modena said yesterday in 
another thread, "pay attention to naming; it will save you 
tons of grief".)

> 	pClassPtr^.VirtualMethod;  { executes Descendant.VirtualMethod, right? }
> 
> 
> Would this still work?
> 
> 	var
> 		Ptr	: Pointer;
> 		Classptr: pClass;
> 		Descend	: pDescendant;
> 
> 	Classptr := Descend;
> 	Ptr := Classptr;
> 	pClass(Ptr)^.Virtualmethod;  { still execute Descendant.VirtualMethod? }
> 
> In my code, which I will not post yet, ...

Well, much of the trouble for us in these snippets is
that we don't know if you've done many of the things needed
to make any of this code work.

1.  Unless you have made a correct call to "New(...)" you haven't a
    chance of this working.  Remember, you are working with pointers.
    This is very different from declaring "A : TClass;".  The latter
    forces the compiler to allocate the static memory for "A".
    When you use pointers, the compiler only puts aside sizeof(pointer)
    for the dynamic variable.  You are responsible for allocating
    the proper amount of memory for that dynamic (pointer) variable.
    Therefore, you must call "New(...)".  Read about the extension
    to the "New()" function in relation to objects.

2.  Once you follow an example from the source code provided 
    with TP/BP, you'll be able to test some of these ideas.
    You already have the notion that you can typecast -- that's good.

    You can try the following:

    type
      PBase = ^TBase; 
      TBase = object
        constructor Init(...);
        destructor  Done; virtual;
        function    IsA: string; virtual;
      end; 

      PDerived = ^TDerived;
      TDerived = object
        constructor Init(...);      { if necessary }
        destructor  Done; virtual;  { if necessary }
        function    IsA: string; virtual;
      end; 
      ...
      { provide method *definitions* -- learn }
      { the lingo -- such as ...              }

      function TBase.IsA: string;
      begin
        IsA := " is an instance of TBase.";
      end;

      function TDerived.IsA: string;
      begin
        IsA := " is an instance of TDerived.";
      end;
      ...

    var
      aBase    : PBase;
      aDerived : PDerived; 
     
    begin
      aBase := New(PBase, Init(...));
      Writeln("aBase", aBase^.IsA);

      aBase := New(PDerived, Init(...));
      Writeln("aBase", aBase^.IsA);

      { try extending this by trying different }
      { typecasts and with the variable        }
      { "aDerived" -- see what happens.        }

      { properly dispose of the instance(s)    }
      Dispose(aBase, Done);

    end.


Others may have more to say on this, and some may castigate 
me for being too harsh.  C'est la vie.

Paul Furbacher
pf@bilbo.bio.purdue.edu
Newsgroups: comp.lang.pascal