cbe*_*bel 6 c++ design-patterns c++11
本书的头部优先设计模式的战略模式的一个例子是在[ 这里 ]用C++编写的.我正在练习将其转换为C++ 11风格,根据有效的GoF模式,使用C++ 11和Boost,如下所示.
该嘎嘎行为:
struct Quack {
static void quack()
{
std::cout << __FUNCTION__ << std::endl;
}
};
struct MuteQuack {
static void quack()
{
std::cout << __FUNCTION__ << std::endl;
}
};
Run Code Online (Sandbox Code Playgroud)
该飞的行为:
struct FlyWithWings {
public:
static void fly()
{
std::cout << __FUNCTION__ << std::endl;
}
};
struct FlyNoWay {
public:
static void fly()
{
std::cout << __FUNCTION__ << std::endl;
}
};
Run Code Online (Sandbox Code Playgroud)
该鸭层次:
class Duck
{
public:
typedef std::function<void(void)> QUACK;
typedef std::function<void(void)> FLY;
public:
Duck(const QUACK &q, const FLY &f)
: m_Quack(q), m_Fly(f) {}
virtual ~Duck()
{
}
void perform_quack()
{
m_Quack();
}
void perform_fly()
{
m_Fly();
}
protected:
QUACK m_Quack;
FLY m_Fly;
private:
Duck(const Duck&) = delete;
Duck& operator=(const Duck&) = delete;
};
class MallardDuck
: public Duck
{
public:
MallardDuck()
: Duck(&Quack::quack, &FlyWithWings::fly)
{
}
};
class PaintedDuck
: public Duck
{
public:
PaintedDuck()
: Duck(&MuteQuack::quack, &FlyNoWay::fly)
{
}
};
Run Code Online (Sandbox Code Playgroud)
到目前为止,客户运作良好.
int main()
{
MallardDuck x1;
x1.perform_quack();
x1.perform_fly();
PaintedDuck x2;
x2.perform_quack();
x2.perform_fly();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
现在我想扩展到一个新的类RubberDuck,以鸭层次,并RubberDuck采用了新飞的行为FlyWithRocket具有对象的状态.如下:
一个新的Fly行为:
class FlyWithRocket {
public:
FlyWithRocket() : m_Energy(3) {}
void fly()
{
if(m_Energy > 0)
{
fly_with_rocket();
--m_Energy;
}
else
{
fly_out_of_energy();
}
}
private:
void fly_with_rocket()
{
std::cout << __FUNCTION__ << std::endl;
}
void fly_out_of_energy()
{
std::cout << __FUNCTION__ << std::endl;
}
unsigned int m_Energy;
};
Run Code Online (Sandbox Code Playgroud)
一种新的鸭子类型:
class RubberDuck
: public Duck
{
public:
RubberDuck()
: Duck(&MuteQuack::quack, std::bind(&FlyWithRocket::fly, std::ref(m_flyrocket)))
, m_flyrocket()
{
}
private:
FlyWithRocket m_flyrocket;
};
Run Code Online (Sandbox Code Playgroud)
从现在起我想知道成员初始化顺序的规则.基数Duck在成员之前初始化m_flyrocket,但请注意,使用尚未Duck初始化的绑定初始化基数m_flyrocket.因为我在VS2013中运行它,这在运行时没有错.
但是代码实际上不安全吗?如果没有,我怎么能修改为更好的设计?
It's not safe, but it's unlikely to break unless you call m_Fly() from the base class constructor.
You can easily avoid this though, by either:
giving the base class constructor a dummy or default-constructed std::function, and re-assigning m_Fly to your bind functor in the derived class constructor
RubberDuck()
: Duck(&MuteQuack::quack, std::function<void()>())
{
m_Fly = std::bind(&FlyWithRocket::fly, std::ref(m_flyrocket));
}
Run Code Online (Sandbox Code Playgroud)making FlyWithRocket a functor itself (just rename void fly to void operator()) and passing it by value instead of keeping a private member (it will be owned by the m_Fly function object, and you can access it via std::function::target<FlyWithRocket>() if you need)
class FlyWithRocket {
public:
FlyWithRocket() : m_Energy(3) {}
void operator() () {
// ...
RubberDuck()
: Duck(&MuteQuack::quack, FlyWithRocket()) {}
Run Code Online (Sandbox Code Playgroud)