Przykład Strategy Pattern z książki, Head First Design Patterns, został napisany w języku C++ pod numerem [here]. Ćwiczę, aby przekształcić go w stylu C++ 11 zgodnie z Effective GoF Patterns with C++11 and Boost, jak pokazano poniżej.Wzór strategii C + 11 ze stanem
Znachor zachowanie:
struct Quack {
static void quack()
{
std::cout << __FUNCTION__ << std::endl;
}
};
struct MuteQuack {
static void quack()
{
std::cout << __FUNCTION__ << std::endl;
}
};
Fly zachowanie:
struct FlyWithWings {
public:
static void fly()
{
std::cout << __FUNCTION__ << std::endl;
}
};
struct FlyNoWay {
public:
static void fly()
{
std::cout << __FUNCTION__ << std::endl;
}
};
Duck hierarchia:
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)
{
}
};
Jak na razie dobrze, klient działa dobrze.
int main()
{
MallardDuck x1;
x1.perform_quack();
x1.perform_fly();
PaintedDuck x2;
x2.perform_quack();
x2.perform_fly();
return 0;
}
Teraz chciałbym przedłużyć do nowej klasy RubberDuck
do Duck hierarchii, a RubberDuck
wykorzystuje nowe zachowanie muchy FlyWithRocket
który ma stan obiektu. W następujący sposób:
Nowa Fly zachowanie:
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;
};
Nowa Duck typ:
class RubberDuck
: public Duck
{
public:
RubberDuck()
: Duck(&MuteQuack::quack, std::bind(&FlyWithRocket::fly, std::ref(m_flyrocket)))
, m_flyrocket()
{
}
private:
FlyWithRocket m_flyrocket;
};
Od teraz zastanawiam się, że zasada kolejności inicjalizacji użytkownik . Podstawa Duck
inicjuje przed elementem m_flyrocket
, ale należy pamiętać, że podstawa Duck
została zainicjowana wiązaniem m_flyrocket
, które nie zostało jeszcze zainicjowane. W wyniku uruchomienia w VS2013 działa to bezbłędnie w czasie wykonywania.
Ale czy kod właściwie nie jest bezpieczny? Jeśli nie, jak mogę zmodyfikować projekt na lepszy?
Głównym pytaniem jest „przechodzi non-zainicjowany obiektu do konstruktora niezdefiniowanej zachowanie? ".Przypuszczam, że w większości przypadków powinno to działać tak długo, jak nie masz dostępu do niego podczas budowy, ale ta odpowiedź pokazuje, że jest to niezdefiniowane zachowanie, więc nie jest bezpieczne: http://stackoverflow.com/a/22203006/104774 – stefaanv