| L B (3806) | |||||
It took me a moment to understand your CUnits example. By Extending is with e.g. classes Inches, Feet, Pounds, Tons, Miles, Quarts, Celsius, Fahrenheit, etc. I could see how that *might* make sense, but what if you wanted To/From English and To/From MyNewUnit and To/From ThatGuysUnits? Would you not then have to adjust CUnits? At that point, if you called one of the new functions on an instance from a plugin that was compiled before the new functions were added, would that not cause problems? Basically, I'm trying to make it so that interactions between classes happen as close to the class types in question as possible. One problem I can't easily solve is cross-plugin interaction - that is, a relationship that cannot be solved via having sub-plugins or the like. I think in this case I will have to rely on the One Definition Rule and have the main game detect when two plugins have mismatched versions. As long as the classes each plugin rely on have the same compatibility version number, the plugins should be able to load even if one was updated without the other caring. I appreciate your arguments, they get me to face problems that I haven't yet but that i would eventually run into later. I've solved tiny majority now, the rest should be the easy part - rendering (oh the pain! The agony!). | |||||
|
|
|||||
| TheIdeasMan (1753) | ||||||
The Pollinate code is in the Bee class. The Living class has a virtual function declaration of PollinateMe. The Animal class has a PollinateMe function that returns false. Flowers have their specific PollinateMe functions in their own class. Just wondering whether this is a trade off - RTTI or casting, versus virtual function declarations in a base class, with virtual function definition where needed. With the Units conversion tree, I had the strategy of always converting (by calculation) from the original unit to an intermediate unit, then to the target unit. For example, to convert from yards to feet, I convert from yards to metres (always metres, no matter what the original was), then from Metres to Feet. It seems strange at first - why not just divide by 3.0? The answer is that, if there are n original units (metric say) & n target units (imperial) and I want to be able to convert between any of them, I now only need 2(n-1) conversion functions, as opposed to n squared conversion functions. I should also point out that next level in the Units tree would have CDistance, CAngle, CArea, CVolume etc. Then after that there is specific units classes like metres, feet, yards,mm, cm etc. It is at this level the conversion functions exist. And, all values used by the code are forced to go through this conversion process - there is no where I use a double as an argument to any function. Values used by the code everywhere are always the metric base units like metres, radians, Sqmetres etc. I don't even keep the original value, it's easier not to keep track of it, and convert it back again on output. Once input conversion is done, there is no need to do any more conversion, until output conversion is needed. So for this question:
No, because the interface always only needs those 2 functions. And a pointer to CFeet is a valid pointer to CUnits. The virtual functions to convert from Feet to Metres and vice versa are in the Feet Class. Maybe the example is too simplistic to compare to what you are doing, because it only needs 2 functions in the interface.
As long as any Units plugin extends the Units tree it should work fine, because the actual conversion functions are in the classes that are added, the interface remains the same. What did you think of my analogy between your code and the Unix System example? And my Mediator design proposal?
Well you could have the virtual function definitions much lower down the tree, but you would have to redefine more (all?)of them because they aren't being inherited. With the idea of having to have an AcquireMe function (that returns false because that is breaking the rules) in the Monster or Enemy class, I am thinking there may be some other funky / clever combination of Design Patterns that might improve this. I did think about putting the Actions into the class that uses them (instead of an Action tree), but the Execute function in Mediator needs to be declared with a pointer to Action. Might need to ruminate on that a bit more.
It is good for me too, most of my stuff is mathematical - converting a formula to code is not that hard generally. Other things I am designing involve storing 5 million 3d points, but still be able to carry out operations on any subset of those. Anyway it's 3.15am again here in Melbourne, Australia, so I will sign off for now. Cheers | ||||||
|
|
||||||
| L B (3806) | |||||||||||||||
| |||||||||||||||
|
Last edited on
|
|||||||||||||||
| TheIdeasMan (1753) | ||||||||||||||||
Yes, because of these: Two times conversion.
This works because of the VTABLE.
The function declaration:
The function call:
At one stage I was going to overload ToMetric:
But then I found out about the VTABLE, and how to take advantage of it. I discovered that I could just have declare 1 virtual function with pointers to the base class. It is exactly the same with my Bee example. The vector is of pointer to Living things, but it is loaded with pointers to Bear, Tiger, HoneyBee and BumbleBee. The Pollinate function is also declared to take a LivingThing pointer parameter and quite happily deals with these various types as arguments, and calls the right function. I am trying to find the link where I read about it. This isn't the one I read originally - but it will do. Article wrote:
Funnily enough it is found here: LOL :D http://www.cplusplus.com/doc/tutorial/polymorphism/ This is a VERY handy feature. It saves you from RTTI, casting, function overloading, and other kinds of complexity. I have mentioned this several times - just wondering whether you do understand this now?
For the same reason as quoted in the article.
Instead of having PollinateMe declared in LivingThing and defined in Animal, you could have PollinateMe defined in each Animal. But this is crazy (my alternative idea) because you should make use of inheritance, not defy it. Maybe it is the names of the functions that provide some level of confusion. You could have a virtual function bool IsFlower in LivingThing, with redefinitions in Animal & Flower. But that is exactly the same thing, with a different name.
OK, maybe you had 1 UserGroupManager that dealt with all the users and all the groups - hey presto a Mediator Pattern!! However, in your Bee example, You had BeeManager, FlowerManger, RockManager and the Tick function is overloaded to do disparate things (Display, Wear to the rock, Pollinate). Presumably there would be a AnimalManager as well. This translates to UserManager & GroupManager in the Unix example, or PlayerManager & EnemyManager & TileSurfaceTypeManager & ResourceManager plus overloaded functions for the Actions in the Game example. With my use of the virtual functions, function overloading is avoided.
Ok, it depends what the rules are. I meant Acquire to be for resources such as Medipack or Ammo, you could have CreateMinion to domesticate a monster. We haven't had much input from other senior members on this site, I will have a go at asking these questions on LinuxQuestions, if that is all right? Do you mind if I point them to this thread? | ||||||||||||||||
|
|
||||||||||||||||
| L B (3806) | |||||||||
| |||||||||
|
Last edited on
|
|||||||||
| TheIdeasMan (1753) | |
|
Ok, I was trying to avoid over explaining things to someone who knows much more than me - I mentioned that a couple of times, and you said you appreciated my comments. But your replies weren't telling me you understood the same way as me. I understood your scenario, I guess we just disagree on which is better. So, truce if you like. Thanks for spending all this time explaining your side, and really good luck with your project, and your studies. Cheers. | |
|
|
|