Code Review

Can someone review my code and let me know if there are any big mistakes. The program compiled correctly, but I just wanted to know if I correctly handled pointers and classes. I am not fluent in identifying memory leaks.

The example comes from "Head First Design Patterns". Basically, my code implements the strategy pattern.

Ducks is the abstract class that MallardDuck and RubberDuck implement.
FlyBehavior and QuackBehavior are the interface classes, which FlyWithWings, FlyNoWings, and Quack implement.

Finally, the program was created in QT, but should run in normal compliers after stripping the headers and basic setup code.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#include <QCoreApplication>
#include <iostream>

using namespace std;

class FlyBehavior {
public:
    virtual void fly() = 0;
};

class QuackBehavior {
public:
    virtual void quack() = 0;
};

class FlyWithWings : public FlyBehavior {
    void fly() {
        cout << "I can fly" << endl;
    }
};

class FlyNoWings : public FlyBehavior {
    void fly() {
        cout << "I cannot fly" << endl;
    }
};

class Quack : public QuackBehavior {
    void quack(){
        cout << "I can quack" << endl;
    }
};

class Duck {
public:
    FlyBehavior *flyBehavior;
    QuackBehavior *quackBehavior;

    void performFly() {
        flyBehavior->fly();
    }

    void performQuack(){
        quackBehavior->quack();
    }

    void performSwim(){
        cout << "All Ducks Swim!" << endl;
    }
};

class MallardDuck : public Duck {
public:
    MallardDuck(){
        flyBehavior = new FlyWithWings;
        quackBehavior = new Quack;
    }
    ~MallardDuck(){
        delete flyBehavior;
        delete flyBehavior;
    }
};

class RubberDuck : public Duck {
public:
    RubberDuck(){
        flyBehavior = new FlyNoWings;
        quackBehavior = new Quack;
    }
    ~RubberDuck(){
        delete flyBehavior;
        delete flyBehavior;
    }
};


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    MallardDuck duck1;
    RubberDuck duck2;
    Duck *duck3 = new MallardDuck();

    duck1.performFly();
    duck1.performQuack();
    duck1.performSwim();

    duck2.performFly();
    duck2.performQuack();
    duck2.performSwim();

    duck3->performFly();
    duck3->performQuack();
    duck3->performSwim();

    return a.exec();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include <iostream>
#include <memory>
#include <typeinfo>

struct FlyBehaviour {

    // for polymorphic delete, a virtual destructor is required
    virtual ~FlyBehaviour() = default ;

    // note: see 'base_of_five_defaults'
    // http://en.cppreference.com/w/cpp/language/rule_of_three
    // copy/move constructor/assignment

    virtual void fly() = 0;
};

struct QuackBehaviour {

    virtual ~QuackBehaviour() = default ;
    // ...

    virtual void quack() = 0;
};

struct FlyWithWings : public FlyBehaviour {

    // override: see http://www.stroustrup.com/C++11FAQ.html#override
    void fly() override { std::cout << "I can fly\n" ; }
};

struct FlyNoWings : public FlyBehaviour {

    void fly() override { std::cout << "I can't fly\n" ; }
};

struct Quack : public QuackBehaviour {

    void quack() override { std::cout << "I can quack\n" ; }
};

// note: all the behaviour classes are stateless right now.
// we assume that they may not remain stateless in future,
// so individual behaviour objects, solely owned by a duck, would be required
class Duck {

    public:

        virtual ~Duck() = default ;

        // not copyable
        Duck( const Duck& ) = delete ;
        Duck& operator= ( const Duck& ) = delete ;

        // moveable
        Duck( Duck&& ) = default ;
        Duck& operator= ( Duck&& ) = default ;

        // unique_ptr: http://www.stroustrup.com/C++11FAQ.html#std-unique_ptr
        Duck( std::unique_ptr<FlyBehaviour> fly_behaviour,
              std::unique_ptr<QuackBehaviour> quack_behaviour )
            : fly_behaviour( std::move(fly_behaviour) ),
              quack_behaviour( std::move(quack_behaviour) ) {}

        void fly() { if(fly_behaviour) fly_behaviour->fly() ; }
        void quack() { if(quack_behaviour) quack_behaviour->quack() ; }
        void swim() { std::cout << "All Ducks Swim!\n" ; }

    private:
        std::unique_ptr<FlyBehaviour> fly_behaviour ;
        std::unique_ptr<QuackBehaviour> quack_behaviour ;
};

class MallardDuck : public Duck {

    public:
        MallardDuck() : Duck( std::make_unique<FlyWithWings>(), std::make_unique<Quack>() ) {}
};

class RubberDuck : public Duck {

    public:
        RubberDuck() : Duck( std::make_unique<FlyNoWings>(), std::make_unique<Quack>() ) {}
};

int main()
{
    MallardDuck mduck;
    RubberDuck rduck;

    Duck* ducks[] = { std::addressof(mduck), std::addressof(rduck) } ;

    for( Duck* d : ducks ) {

        std::cout << "\nI am " << typeid(*d).name() << "\n\n" ;
        d->fly() ;
        d->quack() ;
        d->swim() ;
        std::cout << "-------------\n" ;
    }
}

http://coliru.stacked-crooked.com/a/a4aa5f688287624e
Topic archived. No new replies allowed.