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,4a5bab72e3ac47fc X-Google-Attributes: gid103376,public X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news1.google.com!news2.google.com!fu-berlin.de!uni-berlin.de!not-for-mail From: "Dmitry A. Kazakov" Newsgroups: comp.lang.ada Subject: Re: Dynamich Dispatching... Date: Mon, 4 Oct 2004 10:02:20 +0200 Message-ID: <18qpcb693v2zz$.1es3pcrwk4eiu$.dlg@40tude.net> References: Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit X-Trace: news.uni-berlin.de U/0Og16AYuCtEMDF1cpivwv3g5VTamMkCo1xsdbG3PthNUme8= User-Agent: 40tude_Dialog/2.0.12.1 Xref: g2news1.google.com comp.lang.ada:4643 Date: 2004-10-04T10:02:20+02:00 List-Id: On Sat, 2 Oct 2004 17:39:15 +0200, Rick Santa-Cruz wrote: > I know what to understand about Dynamic Dispatching, but with the following > example in Ada I have some problems to understand the whole thing: > > -- package Objects > package Objects is > type Object is abstract tagged private; If you plan Objects to be always constructed using a call to some constructor function, make sure that they will: type Object (<>) is abstract tagged private; This will prevent declarations like: X : Derived_Object; -- No initial value given > type Object_Ptr is access all Object'Class; Avoid pointers, where possible. > procedure Draw(O: Object) is abstract; > > procedure Set_Text(O: in out Object; Text: String); > function Get_Text(O: Object) return String; > > private > type Object is abstract tagged record > Text: String(1..50); Consider bounded and unbounded strings here. Note also that if in the future you will need initialization/finalization, then Object should better be a descendant of Ada.Finalization.Controlled: type Object is abstract new Ada.Finalization.Controlled with record Further, if public view of Object remains just tagged, while in the full view it is derived from Ada.Finalization.Controlled, then in effect it will be practically impossible to derive from Object in non-children packages. So, to expose or not Ada.Finalization.Controlled as the base is an important decision. > end record; > end Objects; [snip] > -- package Circles: > with Objects; > use Objects; > > package Circles is Probably it should be a child package of Objects, especially if it needs to look into Object's privates. > type Circle is new Object with private; > > procedure Draw(C: Circle); > > package Constructor is > function Create(Text: String; Radius: Integer) return Circle; > end Constructor ; You do not need a nested package here. > private > type Circle is new Object with record > Radius: Integer; > end record; > end Circles; [snip] > -- main-procedure: > with Ada.Text_IO; > with Objects; > with Circles; > > procedure Main is > procedure Call_Dynamic(Object_Ptr: Objects.Object_Ptr) is > begin > Objects.Draw(Object_Ptr.all); > end Call_Dynamic; > C2: Circles.Circle; > begin > C2 := Circles.Constructor.Create("Circle1",50); > Call_Dynamic(new Circles.Circle'(C2)); This is a memory leak. You allocate an object, but never destroy it. Avoid pointers! (:-)) > end Main; > > My question is now, why with Call_Dynamic I call the Draw-procedure in the > package Circles, although in the body of Call_Dynamic I directly call the > Method in the Objects Package? You call a dispatching procedure. When its argument is class-wide, which is the case, because Object_Ptr is a pointer to Object'Class, then the target is selected according to the actual type tag, which is in your case Circle. > Surely it is syntactly correct, cause there > is an abstract mehtod Draw in the Objects-Package, but I don't understand > why such work with classes in different packages. I tested the same, when > all classes are in the same package and surely it worked too, and for me and > the understanding of dynamic-dispatching this is clear. How does this > internally work with the different-package approach as described above in > the source-code? You have used a qualified expression Circles.Circle'(C2) in new, which allocates a new object of Circle and initializes it with the value of C2. Then a pointer to this new object is taken and "converted" to a class-wide pointer Object_Ptr. The result is passed to Call_Dynamic. Where it is dereferenced to Object'Class, on which dispatching Draw is called. The dispatching call gets the tag (->Circle), looks into the dispatching table of Draw and finds there Draw for Circle (an override of Object.Draw). That is called. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de