8 回答
Try using new C++11 feature - strongly typed enumerations. Thanks to it you will not have name collisions and you will end up with really strong type system.
You can use enum class for this
enum class State
{
Accelerating,
Breaking,
Stopped
};
Then you'd refer to it as State::Breaking as you wanted. This of course requires c++11, see http://en.wikipedia.org/wiki/C%2B%2B11#Strongly_typed_enumerations
An alternative I found was to, instead of namespace, use classes, but the problem is this way the project is not clear enough and classes can be instantiated. (Although I can cheat this problem with private constructors)
class GameCharacter {
public:
class MovingState {
MovingState();
/* or, in C++11:
* MovingState() = delete;
*/
public:
enum State {
Running,
Walking,
Stopped // Referred as GameCharacter::MovingState::Stopped.
};
};
class DrivingState {
DrivingState();
/* or, in C++11:
* DrivingState() = delete;
*/
public:
enum State {
Accelerating,
Breaking,
Stopped // Referred as GameCharacter::DrivingState::Stopped.
};
};
...
};
this works, but I'm not very clear if this is the best solution. I think there should be another way. I want opinions. What do you think?
In C++1x (the new version of C++ that was standardised last year), you can use strongly typed enumerations, which put the identifiers in the scope of the enum class itself (among other improvements). These are declared with enum class
:
class GameCharacter {
public:
enum class State {
Running,
Walking,
Stopped // Referred to as GameCharacter::MovingState::Stopped.
};
...
};
In the meantime, if you're stuck with a C++03 compiler or want to retain compatibility, just use class
instead of namespace
and declare the constructor private as you suggested in your own answer. You can make the entire class
private if the outside world doesn't need to see it.
This sounds like a job for C++11's Strongly Typed Enumerations.
class GameCharacter {
public:
enum class MovingState {
Running,
Walking,
Stopped
};
...
void f(Movingstate m) { if (m == MovingState;:Running) ... }
};
void f() { if (mm == GameCharacter::MovingState::Running) ... }
If you use C++11, you can use
class GameCharacter {
public:
enum class DrivingState { Accelerating, Breaking, Stopped };
enum class WalkingState { Stopped, Running, Walking };
DrivingState driving_state() { return ds_; }
void set_driving_state(DrivingState ds) { ds_ = ds; }
WalkingState walking_state() { return ws_; }
void set_walking_state(WalkingState ws) { ws_ = ws; }
DrivingState ds_;
WalkingState ws_;
};
int main() {
GameCharacter g;
g.set_walking_state(GameCharacter::WalkingState::Stopped);
g.set_driving_state(GameCharacter::DrivingState::Stopped);
return 0;
}
You can use a struct instead of a namespace if you are unable to use C++11 strongly typed enums:
class GameCharacter {
public:
struct MovingState {
enum Enum {
Running,
Walking,
Stopped
};
}
...
};
This was something that we adopted for a while (until C++11 support) as it can be used everywhere unlike the namespace trick.
If you have so much in your class that you feel you need to sub-categorise it into namespaces, then your class has too many things.
You should move stuff out of it. In particular all these enums don't need to be members of a class. Why not keep them in the same namespace that the class is in?