From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Thread: 103376,308a261188818cce X-Google-Attributes: gid103376,public,usenet X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news2.google.com!news4.google.com!feeder3.cambrium.nl!feed.tweaknews.nl!not-for-mail From: Ludovic Brenta Newsgroups: comp.lang.ada Subject: Re: Pointers explained? References: <1185817996.143086.317990@g12g2000prg.googlegroups.com> <1185818189.689914.159900@x40g2000prg.googlegroups.com> Date: Mon, 30 Jul 2007 21:05:15 +0200 Message-ID: <87vec1hfv8.fsf@ludovic-brenta.org> User-Agent: Gnus/5.110006 (No Gnus v0.6) Emacs/21.4 (gnu/linux) Cancel-Lock: sha1:uwLeR8fe/Dnb+th1TVWfVQMcIgc= MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Organization: Tele2 X-Trace: DXC=82eE033c^d=fa3^M shaunpatterson@gmail.com writes: > Hi > > I'm still relatively new to Ada -- coming from a strong C++ > background. Some of this may seem stupid - and feel free to point it > out to me. I am using Ada 95 - GNAT Pro 3.16a1 > > I have a message factory I've been screwing around with (converting > it from Ada to C++). > > I basically have an abstract message type: > > type Message is abstract tagged null record; > type Message_Class is access all Message'Class; > > then all other messages are derived from this. > > Now from my factory create method, I'm returning a Message_Class. > This message_class is stored in another record to be handled again > later: > > type CallbackEvent is > record > msg : Message_Class; > ... > end record; > > > Now my basic problem -- or not really a problem -- is that to create > the Message_Class I have to use "new" and allocate and deallocate > memory. > > Now - my solution was to re-write my message factory to return a > type Message'Class. However, I went to change my callback structure > to: > > type CallbackEvent is > record > msg : Message'Class > end record; > > and I get the message "unconstrained subtype in component declaration" > > So, I'm assuming the compiler just doesn't know how to big this > message is. that's why I believe i should use a pointer (the > Message_Class type) However, I cannot find a way of converting > between a Message'Class to a Message_Class; > > It appears that the only way to get a Message_Class is by some where > in the code using a "new" > > Is this assumption correct? I think this is both a language issue and a design issue. >From the language standpoint, your assumption would be correct had you declared Message_Class thus: type Message_Class is access Message'Class; This declares a "pool-specific" access type, and the only way to create values of this type is by calling "new" which will allocate from a storage pool (there is a default storage pool, but you could create your own). But, your actual declaration reads: type Message_Class is access all Message'Class; The "all" keyword makes this a "general" access type, meaning it can take access values of objects that are in any pool, or on the stack, or in the data segment. So, there are two ways to create values of this type: with "new" or by means of the Access attribute, like this: declare M : aliased Message'Class := Factory; -- Note: M is on the stack Event : Callback_Event := (Msg => M'Access); begin ... end; Note that, before you can take the 'Access of an object such as M, you must declare it as aliased. (In C++, everything is implicitly aliased. In Ada, aliasing is explicit and only occurs when you say it does). Now, from a design standpoint, I don't think you really want to record access values for Messages on the stack or data segment, do you? In which case, the pool-specific access type and mandatory call to "new" are really what you want. So, how about this: type Message is abstract tagged null record; type Message_Class is access Message'Class; type Message_Type is (A, B, C); function Factory (Kind : Message_Type) return Message_Class is begin case Kind is when A => return new Message_A'(...); when B => return new Message_B'(...); when C => return new Message_C'(...); end case; end Factory; function Factory (Kind : Message_Type) return Callback_Event is begin return (Msg => Factory (Kind), ...); end Factory; HTH -- Ludovic Brenta.