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=unavailable autolearn_force=no version=3.4.4 X-Received: by 10.224.59.205 with SMTP id m13mr438127qah.7.1371088015429; Wed, 12 Jun 2013 18:46:55 -0700 (PDT) X-Received: by 10.49.116.115 with SMTP id jv19mr1019837qeb.22.1371088015329; Wed, 12 Jun 2013 18:46:55 -0700 (PDT) Path: eternal-september.org!reader01.eternal-september.org!reader02.eternal-september.org!news.eternal-september.org!news.eternal-september.org!mx05.eternal-september.org!feeder.eternal-september.org!usenet.blueworldhosting.com!npeer01.iad.highwinds-media.com!news.highwinds-media.com!feed-me.highwinds-media.com!ch1no5524582qab.0!news-out.google.com!y6ni1854qax.0!nntp.google.com!ch1no5524577qab.0!postnews.google.com!glegroupsg2000goo.googlegroups.com!not-for-mail Newsgroups: comp.lang.ada Date: Wed, 12 Jun 2013 18:46:55 -0700 (PDT) In-Reply-To: <78030778392775583.757462tc.schmidt-gmx.net@news1.open-news-network.org> Complaints-To: groups-abuse@google.com Injection-Info: glegroupsg2000goo.googlegroups.com; posting-host=66.126.103.122; posting-account=duW0ogkAAABjRdnxgLGXDfna0Gc6XqmQ NNTP-Posting-Host: 66.126.103.122 References: <78030778392775583.757462tc.schmidt-gmx.net@news1.open-news-network.org> User-Agent: G2/1.0 MIME-Version: 1.0 Message-ID: <96caa993-0ba4-47da-b337-9aa1c7068029@googlegroups.com> Subject: Re: Howto declare an Ada container with access to objects of a class hierachy From: Adam Beneschan Injection-Date: Thu, 13 Jun 2013 01:46:55 +0000 Content-Type: text/plain; charset=ISO-8859-1 X-Received-Bytes: 5880 Xref: news.eternal-september.org comp.lang.ada:15738 Date: 2013-06-12T18:46:55-07:00 List-Id: [Sorry if this is a double post. Google is being obstinate.] On Wednesday, June 12, 2013 5:43:22 PM UTC-7, Thomas Schmidt wrote: > Hi, > > Hoping this Is the right newsgroup for asking my question. Yes, it is. Welcome. > I want to set up a hashed set of accesses (allocated from heap) to objects > of a given class hierarchie (the top class may f.e. be called "Top"). I > decided to use "Ada.Containers.Indefinite_Hashed_Sets". The hash method > should be a primitive which may be overwritten by derived classes. I've > declared Tops hash functions formal parameter as of type "access Top". How > do I've to declare the sets Element_Type? I think if I use "Top'Access" it > wouldn't fit the hash functions > parameter type nor could I store objects of classes derived from "Top". First of all: I'm assuming that when you want a set of "accesses to objects", you really mean that you want to work with your own accesses (Ada's term for pointer), and you're going to allocate them yourself with a "new" operator. If the access will be pointing to any object in the hierarchy, then you'd declare an access type like this: type Top_Access is access all Top'Class; The 'Class is needed because a Top_Access can point to any object in the hierarchy. (In some other object-oriented languages, you automatically get a pointer to all classes in the hierarchy and you can't declare something that says "This is a pointer to just this one type and *only* this one type. Ada is different.) Now that you have an access type, you can use it as the Element_Type. However, an *access* type is always a definite type, so you can use Ada.Containers.Hashed_Sets instead of Ada.Containers.Indefinite_Hashed_Sets. To instantiate the generic, you'll need a Hash function and an Equivalent_Elements function. You've declared a Hash function for Top and all of the derived classes. But you need a Hash function that takes a Top_Access as a parameter (since Element_Type will be Top_Access). This is pretty easy to write, though: function Hash (A : not null Top_Access) return Ada.Containers.Hash_Type is begin return A.all.Hash; end Hash; A.all is the object pointed to by A. Its type is a *classwide* type Top'Class -- that is, it is either Top or one of its derived classes. A.all.Hash then calls the Hash function; and since A.all's type is a classwide type, the result is that it will call the correct Hash for whatever the object's type is. Which is what you want. You don't really need .all in this example; you can usually leave it out if there's something else following. function Hash (A : not null Top_Access) return Ada.Containers.Hash_Type is begin return A.Hash; end Hash; You'll also need something to use for Equivalent_Elements. I'm assuming that you've written a function Equiv for Top and its derived types that looks like function Equiv (Left, Right : Top) return boolean; overriding function Equiv (Left, Right : Derived_Type_1) return boolean; and so on. So you could try to write function Equiv (Left, Right : not null Top_Access) return boolean is begin return Left.Equiv (Right.all); end Equiv; (You do need .all after Right here.) The problem is that this will cause a problem if Left and Right are pointing to objects of different types, this will raise an exception. So you'll need to check: with Ada.Tags; --- you'll need this up at the top function Equiv (Left, Right : not null Top_Access) return boolean is begin --if Ada.Tags."=" (Left.all'Tag, Right.all'Tag) -- or just if Ada.Tags."=" (Left'Tag, Right'Tag) then return Left.Equiv (Right.all); else return false; end if; end Equiv; The check is kind of ugly, but I don't know of another way to test whether two class-wide objects are the same type. Now you can instantiate: package Top_Set is new Ada.Containers.Hashed_Sets (Element_Type => Top_Access, Hash => Hash, Equivalent_Elements => Equiv); (If you really didn't want to use accesses, you could instantiate Ada.Containers.Indefinite_Hashed_Sets with Element_Type => Top'Class. You'd have to write your own Hash and Equiv functions that take a Top'Class as parameters, and they'd look similar to the ones I showed you above that take Top_Access as parameters. A *classwide* type is an indefinite type, so you'd need Indefinite_Hashed_Sets here.) I realize this is a bit complicated. Hope this helps, -- Adam