Variable Exposure - Epidemic Alert

Started by
35 comments, last by Holy Fuzz 19 years, 8 months ago
Quote:Original post by Jiia
I almost forgot to ask one other question. Why derive classes as public? As in CCharacter : public CObject. What happens when you derive them private or protected? Again, sorry if this is a dumb question.


;-)
Advertisement
Quote:Original post by snk_kid
Maybe your using the wrong levels of abstraction, i see having CObject type which is the root of all types in a type hierarchy not very useful at all to be honest, it's to abstract to be put into any good use, you end up stuffing data and pushing functionality there where it doesn't actually make any sense.

I'm not sure what you mean. CObject represents a map based object. I don't see it as abstract at all. My point was to allow any number of map object types to be juggled around in all of my routines without ever really knowing or caring what is what. Most routines treat all map objects exactly the same, but their internal behavior is what makes them different.

Quote:Original post by snk_kid
solution look at the standard library bitset [www.sgi.com] and prefer using that instead.

Thanks, but templated classes make me rather ill. And I'm not sure how this would help me, as it is the concept I'm asking about, not bitflags.
Quote:Original post by snk_kid
Quote:Original post by Jiia
But protected is still very useful to include tasks for that class to run on itself. This really does make a lot of sense.


I'm not sure what your saying here.


If I may speak for Jiia, protected member functions are a possible way to implement callbacks. Example, you can publish a "MessagePump" framework class, and give it a protected virtual function OnIdle. The default implementation does nothing, but people may derive from "MessagePump" and implement their own version of OnIdle. The base class code will then call the derived function during its normal processing.

That being said, I wouldn't do anything this way anymore; I'd probably leave it to functors which would get registered with the class, and publish default functors with my nifty MessagePump.
Quote:Original post by Jiia
Quote:Original post by snk_kid
Maybe your using the wrong levels of abstraction, i see having CObject type which is the root of all types in a type hierarchy not very useful at all to be honest, it's to abstract to be put into any good use, you end up stuffing data and pushing functionality there where it doesn't actually make any sense.

I'm not sure what you mean. CObject represents a map based object. I don't see it as abstract at all. My point was to allow any number of map object types to be juggled around in all of my routines without ever really knowing or caring what is what. Most routines treat all map objects exactly the same, but their internal behavior is what makes them different.


Probably calling it CObject may have miss-lead me. You get people having something like an Object type as root of all types in a hierarchy like in java & objective-c, i just dont think it's very useful to base a design on that because an Object is to abstract but thats not what your CObject type represents so don't worry.
I think i should explain what i mean by to abstract to be derived directly from.

Say your problem domain is GUIs and you where focusing on implementing a hierarchy of widgets. Lets start with having a root type for these widgets say you already have an abstract type called Object you use for other problem domains, okay fine we sub-type are widgets from Object type.

Later on you discover that widgets need to implement some basic collision detection so you create a user-defined type that represents the concept of bounds and has an operation that can detect if two bounds have intersected. You've done that you relize that this functionality needs to be through-out the hierarchy of widgets so you end up puting a bounds data member in the Object type and an operation that allows querying/updating/testing etc on the bounds member.

There is one problem does it really make sense for the type Object to have bounds? that depends on which context object is in, the meaning of object is to abstract, it's ambiguous. A much better abstraction would be either to start with an abstract type called widget as the root type, or add a new abstract type derived from the object type also called widget where it makes sense to put a bounds member inside a widget type.

[Edited by - snk_kid on August 3, 2004 6:26:26 PM]
Quote:Original post by Jiia
Thanks, but templated classes make me rather ill. And I'm not sure how this would help me, as it is the concept I'm asking about, not bitflags.


Sorry i wasn't paying much attention on that bit, well i'm bored at the moment so i'll read that bit a bit more closely.

Well you could provide an accessor function that is protected if it doesn't make sense for it to be in the type's interface e.g.

class CBitFlags;class CObject {    ...    CBitFlags   FStatus;    ...protected:    const CBitFlags& getFlags() const { return FStatus; }    CBitFlags& getFlags() { return FStatus; }public:    virtual ~CObject() {}};struct CCharacter : public CObject {   void TakeHealth(int value) {        HurtMe(value);        if(GetHealth() < 0)            getFlags().TurnOn(STATUS_DEAD);    }};


I know your probably thinking what difference does it make but this is just silly example of what can do.
No, I don't derive everything from one type. Kind of pointless, really. CObject only has about 4 or 5 derived children.

In my opinion, GetFlags().TurnOn(STATUS_DEAD) is much uglier than having such protected member variables. Not to mention that functions need to be made to return every interface implimented.

In cases such as this, where the data itself is an interface, I don't understand the point of hiding the data in the first place. I'm not saying it's right, but I'm saying I don't understand why it's wrong.

I also find it nice to have sub-interfaces for related tasks, because it leaves the CObject class less cluttered. For example, I could have a very detailed vector class for force, which does its own bounds checking and updates it's own velocity. All objects can have force, but only characters apply forces to themself. So it only makes sense to allow them to access that interface. That, or privide routines specific to characters in the CObject class. But doesn't this go against your original CObject argument? To not provide extensive routines that are specific to only a single or few derived types? Yet again, I'm giving bad examples; I'm sure you understand what I mean, though.
Quote:
If I may speak for Jiia, protected member functions are a possible way to implement callbacks. Example, you can publish a "MessagePump" framework class, and give it a protected virtual function OnIdle. The default implementation does nothing, but people may derive from "MessagePump" and implement their own version of OnIdle. The base class code will then call the derived function during its normal processing.

That being said, I wouldn't do anything this way anymore; I'd probably leave it to functors which would get registered with the class, and publish default functors with my nifty MessagePump.

The HurtMe() function in my example is what I'm speaking of. HurtMe would be a CObject method, as all CObject types can be hurt. So why not have that as protected? I am the absolute master at dumb examples, but I hope the idea is clear.
Quote:Original post by Jiia
No, I don't derive everything from one type. Kind of pointless, really. CObject only has about 4 or 5 derived children.

In my opinion, GetFlags().TurnOn(STATUS_DEAD) is much uglier than having such protected member variables. Not to mention that functions need to be made to return every interface implimented.


In cases such as this, where the data itself is an interface, I don't understand the point of hiding the data in the first place. I'm not saying it's right, but I'm saying I don't understand why it's wrong.


I'm sorry but like i said before that getFlags wasn't such good example to get the point across.

Think about it thou don't you think that having a data member protected is bit of a contridiction like i was saying in my first post above, by declaring a data member protected your implying that unrelated types/modules can't access but if you sub-type you can, if you do that it may aswell be public but then you need to make sure that the member never changes to avoid updating all other modules and re-compilling & the state invariant is maintained manually.

If the representation really is not going to change ever then make it public because making it protected is silly. Just remember thou that this makes it less extendable in the future but that doesn't mean it's a bad thing because to sub-type from certain concrete types would be plain dumb like sub-typing from the c++ standard library complex type.

So with that in mind i would say only

Quote:Originally by snk_kid
encapsulate the variant/variation.


What do i mean there, well if a representation or even an interface varies statically/dynamically encapsulate it and provide a uniform interface that never changes. This is simillar to the Handle-Body idiom

This is the key to the abstract mechanism, to abstract complexity or variation.
I don't see a big difference between an interface data member and a group of member functions. No data can be modified directly. But you still wouldn't always want outside code to be able to call functions of the interfaces, just as you wouldn't want them to be able to call member functions. You don't agree that this situation happens, often?

A) All or most derived types of the base class must perform a task the exact same way.

B) That task may be implimented in different situations / at different times for each derived type. The tasks may be proceeded and followed by other tasks unique to each type. ie: The base class does not know when the tasks must be executed.

C) No outside routines should ever be allowed to run the tasks, as it would screw up the whole flow of things.

If code is broken up properly, there should be quite a few medium sized functions and interfaces which perform individual tasks. Where do I put these functions and interfaces?
Quote:Original post by Jiia
I don't see a big difference between an interface data member and a group of member functions.


An interface type doesn't have any data members, or any implementation whats so ever (in C++ this would be class with no data members and all methods are pure virtual member functions, in java they have interface types, in objective-C there are protocol types). It just defines a protocol for two parties to participate & be able to communicate with each.

Then there is also the object/instance's interface which is something kind of different that would mean all it's public members.

I think that might the problem because when i was saying interface before i was using it to mean either depending on the context being used.

Quote:Original post by Jiia
No data can be modified directly.


Not sure what you mean, if you make it public, create an instance of that type you can access it directly your code becomes dependant/coupled tightly with it.

Quote:Original post by Jiia
But you still wouldn't always want outside code to be able to call functions of the interfaces, just as you wouldn't want them to be able to call member functions.


You've completely lost me here, what interface do you mean, an interface type or the inteface of an intance, it's public members that is.

Quote:Original post by Jiia
You don't agree that this situation happens, often?

A) All or most derived types of the base class must perform a task the exact same way.

B) That task may be implimented in different situations / at different times for each derived type. The tasks may be proceeded and followed by other tasks unique to each type. ie: The base class does not know when the tasks must be executed.

C) No outside routines should ever be allowed to run the tasks, as it would screw up the whole flow of things.

If code is broken up properly, there should be quite a few medium sized functions and interfaces which perform individual tasks. Where do I put these functions and interfaces?


What do you mean by task?, please be abit more clear.

I'm sort of lost wheather your last post was for or against this discussion.

This topic is closed to new replies.

Advertisement