Deriving from a class used for state-tracking?

Started by
10 comments, last by Grammarye 18 years, 5 months ago
Now it's common that in a class you may have an enumeration of possible states an object of that class can be in. But what about when you derive from this class, and a child needs an extra state? OO design says the parent shouldn't know about its children so putting every possible state in the base class is bad - but how can we achieve our aim in a 'good' way?
Advertisement
Check for the state design pattern, should be loads of resources on the net.
hi,

I don't quite understand your problem :/

class CParent{public:   CParent();   ~CParent();   virtual void SetStates(void);protected:   int state1;   float state2;};class CChild : pulic CParent{public:   CChild();   ~CChild();   virtual void SetStates(void);  // set state3 and call the parent SetState method to set state1 and state2protected:   char *state3;};


Here, the CChild class will have visibility on state1 and state2, and add a third state. If you have a virtual class to set those states, you can store a list of CParent * and you don't have to care of visibility. The program will call the CChild::SetState if it needs.

Well, if this is not what you asked for, then sorry, I didn't understand then ^^
Quote:Original post by paic
I don't quite understand your problem :/


From what i understood he means something like:

struct foo {   enum bar {       CONSTANT1,       CONSTANT2,       CONSTANT3   };   // .....};struct foo2 : foo {   // now he wants to add a new member to the set of bar   // ....};
class CBase{public:enum STATE {NONE,MOVING,WAITING,STOP};virtual void ActOnState();private:STATE m_State;};


Now let's say a child class wants a state called RUNNING, or TURNING, or SHOOT.
That's the problem. It's these enumerations which don't really work with derivation which are the problem.

EDIT: snk_kid beat me to the explanation of my own problem [smile]
Quote:Original post by d000hg
class CBase{public:enum STATE {NONE,MOVING,WAITING,STOP};virtual void ActOnState();private:STATE m_State;};


Now let's say a child class wants a state called RUNNING, or TURNING, or SHOOT.
That's the problem. It's these enumerations which don't really work with derivation which are the problem.

EDIT: snk_kid beat me to the explanation of my own problem [smile]


This is a language limitation of C++, so you don't have a choice. You'll need to use an alternative, like the State Design Pattern. If this is merely an academic exercise for your own edification, you could try using Haskell, which does allow you to extend enumerations,
- k2"Choose a job you love, and you'll never have to work a day in your life." — Confucius"Logic will get you from A to B. Imagination will get you everywhere." — Albert Einstein"Money is the most egalitarian force in society. It confers power on whoever holds it." — Roger Starr{General Programming Forum FAQ} | {Blog/Journal} | {[email=kkaitan at gmail dot com]e-mail me[/email]} | {excellent webhosting}
It's a real-world problem. The state pattern seems a very complex way to fix what seems a simple problem, but I guess that's just the way it is. For applications where the original enumeration is not going to expand often or very much, presumably it's easier 9 times out of ten to just stick all the enumeration values needed by child classes into the base and live with the OO 'hack'?
Why don't you use contants? After all, enumerations only define constants (and suffer the same problem than integer constants).
struct foo {  static const int value1 = 0;  static const int value2 = 1;  static const int value3 = 2;  ...};strut foo2 : public foo{  static const int value4 = 3;  ...};

Of course, you have to give the value for every constant you create - it is not as simple as enumeration values. I see at least one "kind of" hack that will allow you to use a value without explicitely defining it. Something that look like this:
class UniqueValue{public:  operator int() { return (int)this; }  bool operator==(const UniqueValue& value) { return this == &value }};// -- foo#include "UniqueValue.h"struct foo{  static const UniqueValue enum_value_1;  static const UniqueValue enum_value_2;  static const UniqueValue enum_value_3;};// of course, in a cpp file:const UniqueValue foo::enum_value_1;const UniqueValue foo::enum_value_2;const UniqueValue foo::enum_value_3;// -- foo2#include "foo.h"struct foo2 : public foo{  static const UniqueValue enum_value_4;};// and foo.cppconst UniqueValue foo::enum_value_4;

This is of course far from complete, and I'm not even sure that it will compile. It works because each defined UniqueValue is static, and the address of 2 static objects can't be the same.
I guess there is a better way to do this (this way has some heavy problems) but I believe it should work.

Regards,
Some interesting ideas there. Not sure if I can convince our lead programmer of the merits but it definitely looks like something I'll investigate for my own code, when I want states but without a whole FSM approach - for that I probably would follow the state pattern.
Quote:
class UniqueValue{public:  operator int() { return (int)this; }  bool operator==(const UniqueValue& value) { return this == &value }};



I think you forgot a *
operator int() { return (int)*this; }

This topic is closed to new replies.

Advertisement