Call extended type method from base type instance
BlitzMax Forums/BlitzMax Programming/Call extended type method from base type instance
| ||
What ??? .. Well if you want to create a base type, and extend sub objects from that type.. you will start to run in to some problems when you want to return an extended type as its base type. An example of what I mean: You have a gui gadget type, called "guigadget". Now this stores the x,y,width,height and lets any other features for a particular gadget (button,scrollbar,textbox,etc) upto the extended type. Now say we create and return a guigadget, but it is actualy guigadget_button type. How would you then call any methods from the extended type ? Take a look at this code, it might help. This seems like the most viable way to me, but unless Im missing something. Is there a more suitable way of doing this ? Type fruit Field x,y,width,height Field _CallUpdate(f:fruit) Method Update() 'because the base class update is called, we need to use the method caller stored _CallUpdate(Self) End Method End Type Type apple Extends fruit Field brand:String 'creation function Function Create:fruit(x,y,width,height,brand:String) Local a:apple = New apple 'setup properties a.x = x a.y = y a.width = width a.height = height a.brand = brand 'setup class callers a._CallUpdate = apple.CallUpdate Return a End Function 'callers for this class Function CallUpdate(f:fruit) apple(f).Update() End Function 'methods for this class Method Update() Print "update apple, brand = "+brand End Method End Type Type grape Extends fruit Field numberinbunch 'creation function Function Create:fruit(x,y,width,height,bunch) Local g:grape = New grape 'setup properties g.x = x g.y = y g.width = width g.height = height g.numberinbunch = bunch 'setup class callers g._CallUpdate = grape.CallUpdate Return g End Function 'callers for this class Function CallUpdate(f:fruit) grape(f).Update() End Function 'methods for this class Method Update() Print "update grape, number in bunch = "+numberinbunch End Method End Type 'now we can create 1 apple and 1 grape, and return them as the base class. 'if we want to call the update function for either, we can, because it has been mapped using a function pointer. Local fruit1:fruit = apple.Create(0,0,60,60, "golden smith") Local fruit2:fruit = grape.Create(10,10,60,100, 75) fruit1.Update() fruit2.Update() Input "press enter to end" |
| ||
I may be misunderstanding you, but virtual methods take care of this automatically. It doesn't matter whether fruit1 or fruit2 are defined as Fruit objects or the actual types from which they are instantated. Type Fruit Method whatAmI() Abstract End Type Type Apple Extends Fruit Method whatAmI() Print "I am an apple" End Method End Type Type Orange Extends Fruit Method whatAmI() Print "I am an orange" End Method End Type Local fruit1:Fruit=New Apple Local fruit2:Fruit=New Orange fruit1.whatAmI() fruit2.whatAmI() |
| ||
Ah ha.. duh I am stupid XD |
| ||
If you don't have a virtual method in the base type - say when different derived types will implement different methods - then you can check what type the instance is, cast to the proper sub-type and then invoke the method.Strict Type Fruit Method whatAmI() Abstract End Type Type Apple Extends Fruit Method whatAmI() Print "I am an apple" End Method Method howManyWorms() Print "Only a couple of worms" End Method End Type Type Orange Extends Fruit Method whatAmI() Print "I am an orange" End Method Method howJuicy() Print "Very juicy" End Method End Type Local fruit1:Fruit=New Apple Local fruit2:Fruit=New Orange PrintInfo(fruit1) PrintInfo(fruit2) Function PrintInfo(thing:Fruit) thing.whatAmI() If Apple(thing) Local myApple:Apple = Apple(thing) myApple.howManyWorms Else Local myOrange:Orange = Orange(thing) myOrange.howJuicy() EndIf End Function |
| ||
Yeah I knew that one, was looking for a method that didn't require a comparison against each extended type. Because well, it would mean those extended objects couldn't be further extended without modifying alot of function calls. |
| ||
I believe that all methods in BlitzMAX types are virtual or at least Max deals with the virtual business automatically. This means that you don't need to do anything special with the base class's method in order to replace in in a derived type. As a rule, the base class should not be aware of or rely on any derived types in any way. Similarly any functions that accepts an object of the base type as a parameter should not have to know anything about the possible derived types from which the object might actually have been instantated. |
| ||
Robert, I take your point and agree that such independence of the base type from derived types would be ideal. However this pure approach falls down (IMHO) if it leads you to have a lot of properties and methods in the base type that do not apply in some or even most of the derived types. So a competing ideal is that a type only contain or provide those properties and methods that make sense for it. When I want a derived type that introduces a new method say, I don't want to go back through the hierarchy adding it all the way back to the base - abstract or not. And when it is abstract, doesn't each derived type that isn't abstract have to provide an implementation ? So I'm finding that somewhere between the two ideals is what works in practice. I'm still learning about this object stuff so I'm happy to hear a different point of view. I'm working on one project in BlitzMax where there is a deep object hierarchy. Each type in the hierarchy maintains a TList so when I need to apply a method that exists only in a type and its derivatives then I iterate through the appropriate list. I don't iterate through the top level list and check the type before invoking the method if it is appropriate. It is a bit lengthy to show here but when it is done I plan to submit it for comment. Perhaps somebody could come up with a better design. PGF |