From: hartman@ulogic.UUCP (Richard M. Hartman)
Newsgroups: comp.lang.c++
Subject: Re: downcasting (was Re: GOTOo wars)
Date: 9 Oct 92 18:48:21 GMT
Article-I.D.: ulogic.407
Organization: negligable

In article <1992Oct4.114145.21060@ucc.su.OZ.AU> maxtal@extro.ucc.su.OZ.AU (John MAX Skaller) writes:
>In article <1992Oct2.141636.17829@jyu.fi> sakkinen@jyu.fi (Markku Sakkinen) writes:
>>In article <361@ulogic.UUCP> hartman@ulogic.UUCP (Richard M. Hartman) writes:
>>>In article <9227521.28722@mulga.cs.mu.OZ.AU> fjh@munta.cs.mu.OZ.AU (Fergus James HENDERSON) writes:
>>>>hartman@ulogic.UUCP (Richard M. Hartman) writes:
>>>>
>>>>>We're using the NIH Linked List.  When you get something off
>>>>>the list it is just an Object *.  To actually use it you have
>>>>>to downcast it to it's proper (and hopefully Object-derived :)
>>>>>class.  If someone knows a way around this, please let me know
>>>>>and I will *gladly* give up my use of castdown......
>>>>
>>>>The Politically Correct way of doing this, I believe, is to use a template
>>>>linked list class. (Look Ma, no casts! :-)
>>>
>>>That only works if you compiler supports templates.....	:(
>>
>>And templates only help in defining homogeneous container classes.
>>If you really need a heterogeneous list, it's hard to avoid castdowns.
>>

I do not have heterogenous lists, but in order to implement a StudentList
I have to derive from List, which returns Object * (StudentObj is derived
from Object, and can thus be placed on an NIH List).  When I get a 
Student from the List it is an Object * and I have to cast to
StudentObj *.  I know that all members of the list are going to be
StudentObj, but I still have to do the stupid downcast because I am
using SOMEONE ELSE'S List class as a base class.  NIH is the National
Institute Health (why they produced an object heirarchy library I
have NO idea).  The NIH class library is the foundation of the book
"Data Abstraction and Object-Oriented Programming in C++", by
Keith E. Gorlen, Sanford M. Orlow, Perry S. Plexico.  Published
by Wiley.

If I were doing my OWN stuff (and my compiler supported templates)
I could make use of some of this discussion.  However the basic concept
is that all objects derive from "Object".  Generic container classes
take members of type "Object" (or, of course, it's descendants). 
Whether you store homogeneous or heterogenous data in the container
classes is immaterial.  The container classes only know about 
Object, and that is what they return when you use the access
functions.  It is up to you to castdown to the correct type.  The
original topic here WAS whether castdown actually had any purpose,
wasn't it?  (it's been so long.....)

>	For a start, you cant have a heterogenous list or array.

I never said I did.

[ discussion about list of union type omitted ]

>	typedef [A,B,C] *T; // tagged pointer type T

I have never seen this mechanism.  Is it related to templates
(and thus also not supported by my compiler)?

>	There is a second type of list one might consider.
>This list consists of pointers to objects derived from Base.
>Here, polymorphism/inheritance unifies the type: it homogenises
>the type. A list of pointers to Base is homogenous, not
>heteromorphic. After all, all the pointers point to a Base,
>and every object derived from a Base 'isA' Base (or should be
>to be used in this type of list).

Ahhhh.  Here we go.  This is what the NIH library does.  As I
mentioned in my original post, the access functions return
only Object *:

	Object  *List::get() 

to use it I have to do:

	StudentObj *pStu = StudentObj::castdown(myList.get(key));

(note: this mechanism MAY just be some sort of wierdness induced
 by NIH's ideas of what is proper.... as I said originally, if
 there is a better way, PLEASE let me know!)

>	This second type of list has the added advantage
>of allowing INDETERMINATE objects derived from base to
>be pointed to, at the expense of restricting you
>to interfacing via the Base. (Often facilitated by
>virtual functions).

Unless you know in advance what the "real" type is.

>	In both cases we want sound practice, namely, to access
>the list elements by the declared interface only. 

Yes.  

>	The two mechanism can be combined, assuming
>D1, D2, D3 are derived from Base we can have:
>
>	typdef [Base,D1,D2,D3] *T;
>
>and use the Base* for polymorphic calls and the D1, D2 and D3 
>pointers for heteromorphic ones.

Again this construct.  Please explain it further.

For that matter, even if my compiler supports it, how does
use of "T" differ from use of "Base *" if D1, D2 and D3 are
already derived from Base?

>	Downcasting is not required by either of these mechanisms.
>This mechanism should suffice in almost all cases where you 
>think you need a heterogenous list.

Heck, I've got a HOMOGENOUS list.  But to implement StudentList::get()
I have to refer to my parent class (List::get()) which returns an
Object *.  I have to convert it to StudentObj * and return it, 
don't I.  From what I understand you can ALWAYS do:

	Object *pObj = pObjDerived;

but you can't always do:

	ObjDerived *pObjDerived = pObj;

can you?  If you can, then why is there that silly
::castdown() function in the NIH library doing for me?

>	Downcasting does offer something neither the above 
>mechanisms does, and for that reason I am suspicious of it.
>It allows an arbitrarily chosen but finite set of classes
>to be checked for, *as if* they had been declared
>like a tagged pointer, at one local place in the program.
>However at another place, another different set can be
>chosen. Therefore, since the number of such places
>in a program is unbounded, the number of derived classes
>that are special is *UNBOUNDED*.

I don't even follow what you are saying the advantage here
is.  Could you please rephrase it?  I think it may have to
do w/ not understanding what "tagged pointer" means (does it 
refer to that wierd construct you used above?)

>	Now polymorphism already manages an unbounded (arbitrary)
>number of derived classes by homogenising the interfaces
>(that is, by virtual functions). That such restrictions
>are required to have polymorphism operate properly
>in a system built of closed modules seems to indicate to
>me that downcasting perverts the course of type safety.

Nope.  I'm just trying to reuse an already written class (List)
for my own purposes instead of reinventing the wheel, isn't that
what the who point of Object-Oriented Programming was supposed
to be?  The fact that I have to perform unwanted gyrations
to make use of this supposedly generic container class may
just indicate that the NIH library is garbage (an opinion that
I already tend towards....) (if you wish to be generous, please
read "poorly designed" where I have typed "garbage" :)

>	I want to consider what happens in a system
>with dynamic linkage. This can just be dynamic class loading,

Another think I would be interested.  Loading a class from a
file before you know what class is stored there is something I would
very much like to be able to do.

>In C++, the system is broken down into the compilation and linkage stages.
>Although the compiler cannot know about all the classes, the linker
>can, so with suitable cooperation RTTI can be provided to allow
>safe downcasting to operate. In particular, access to the
>complete system inheritance DAG is required.

RTTI?  DAG?  Ya ne ponimaiyu.....

[ from this point on the article seems to go off in directions
  that while interesting don't seem to be related to my original
  query of whether I have been duped into thinking I require
  downcasting when I really don't.... ]



		-Richard Hartman
		hartman@uLogic.COM

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Extensive studies have shown that 93% of all statistics are meaningless.
Newsgroups: comp.lang.c++