patterncppMinor
Defining a certain member function
Viewed 0 times
certainfunctionmemberdefining
Problem
Consider the following:
What I wonder is if
is clearly more typing (and may run into difficulties if I want to redefine it everywhere it is used, e.g. change
This is just an example of course. In reality, I have states like
#include
struct State { virtual ~State() = default; };
struct Drunk : State {
void singWhileDrunk() {std::cout (state)->singWhileDrunk();} // Is this good?
};
int main() {
Person bob;
bob.state = new Drunk;
bob.singWhileDrunk();
// dynamic_cast(bob.state)->singWhileDrunk(); // Using this is better?
}What I wonder is if
Person::singWhileDrunk() should really be defined in Person or not. singWhileDrunk() only has true meaning if the person is drunk, so to define it in Person seems wrong to me. However, it does simplify the code in main(), especially if it is to be used a lot.(dynamic_cast(bob.state)->singWhileDrunk();is clearly more typing (and may run into difficulties if I want to redefine it everywhere it is used, e.g. change
dynamic_cast to static_cast). Another issue I have is that in my program I have many different types of states, each with their own special functions, and to define them all in Person will really bloat the Person class with MANY, MANY functions that don't even seem to belong in Person. So there seems to be pros and cons to both choices and would like to hear what others have to say about this.This is just an example of course. In reality, I have states like
FlySpellState, with the function flies(), which also seems to have no place in Person (since people cannot fly normally), though it could be.Solution
You should never really be doing any manual casting.
Virtual functions usually provide you with the functionality you are looking for.
How about:
Then your code in main is even more trivial:
This is just an example of course. In reality, I have states like FlySpellState, with the function flies(), which also seems to have no place in Person (since people cannot fly normally), though it could be.
Sure. So what you want is a bunch of different states. These states can all be changed when diffent situations apply.
Rather than using
Virtual functions usually provide you with the functionality you are looking for.
How about:
struct State
{
virtual void sing() = 0;
};
struct Drunk: State
{
virtual void sing() { std::cout state;
public:
Person()
: state(new Sober)
{}
void sing()
{
state->sing();
}
void drink()
{
state.reset(new Drunk);
}
void sleep()
{
state.reset(new Sober);
}
};Then your code in main is even more trivial:
int main() {
Person bob;
bob.drink(); // Don't allow manual changes in state.
// Provide actions that internally modify the state of your object.
bob.sing();
bob.sleep();
bob.sing();
}This is just an example of course. In reality, I have states like FlySpellState, with the function flies(), which also seems to have no place in Person (since people cannot fly normally), though it could be.
Sure. So what you want is a bunch of different states. These states can all be changed when diffent situations apply.
struct Action
{
virtual void doAction() {std::cout > actionMap;
Action& getAction(std::string const& action)
{
static Action defaultAction; // Will do Nothing by default.
auto find = actionMap.find(action);
return find == actionMap.end()
? defaultAction
: *(find->second);
}
void sing()
{
getAction("sing").doAction();
}
void fly()
{
getAction("fly").doAction(); // Default do nothing unless you have read the scroll of flying
}
void drink()
{
actionMap["sing"].reset(new Drunk);
actionMap["walk"].reset(new Stumble);
actionMap["talk"].reset(new Slur);
}
void readScrollOfFlying()
{
actionMap["fly"].reset(new FlySpellState);
}
};Rather than using
std::unique_ptr and lots of calls to new. You may want to look up the flyweight pattern.Code Snippets
struct State
{
virtual void sing() = 0;
};
struct Drunk: State
{
virtual void sing() { std::cout << "Singing while drunk.\n"}
}
struct Sober: State
{
virtual void sing() { std::cout << "Singing Opera.\n"}
}
class Person
{
std::auto_ptr<State> state;
public:
Person()
: state(new Sober)
{}
void sing()
{
state->sing();
}
void drink()
{
state.reset(new Drunk);
}
void sleep()
{
state.reset(new Sober);
}
};int main() {
Person bob;
bob.drink(); // Don't allow manual changes in state.
// Provide actions that internally modify the state of your object.
bob.sing();
bob.sleep();
bob.sing();
}struct Action
{
virtual void doAction() {std::cout << "Nothing Happens\n";}
};
class Person
{
std::map<std::string, std::unique_ptr<Action>> actionMap;
Action& getAction(std::string const& action)
{
static Action defaultAction; // Will do Nothing by default.
auto find = actionMap.find(action);
return find == actionMap.end()
? defaultAction
: *(find->second);
}
void sing()
{
getAction("sing").doAction();
}
void fly()
{
getAction("fly").doAction(); // Default do nothing unless you have read the scroll of flying
}
void drink()
{
actionMap["sing"].reset(new Drunk);
actionMap["walk"].reset(new Stumble);
actionMap["talk"].reset(new Slur);
}
void readScrollOfFlying()
{
actionMap["fly"].reset(new FlySpellState);
}
};Context
StackExchange Code Review Q#72087, answer score: 4
Revisions (0)
No revisions yet.