2

I am trying to learn Design Patterns with C++. I am implementing the Program given in the first chapter of OReilly's Head First Design Patterns regarding the Duck problem. Please bear with me, it's quite a long question.

Anyways, I have tried to create the following 2 interfaces:

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

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

Now i have a Duck class, which needs to have instants of the above 2 classes. What I am doing is:

class Duck
{
public:
    FlyBehavior flyBehavior;
    QuackBehavior quackBehavior;
    Duck()
    {

    }

    virtual void display() = 0 ;
    void performQuack()
    {
        quackBehavior.quack() ;
    }

    void performFly()
    {
        flyBehavior.fly() ;
    }

    void swim()
    {
        std::cout << "All ducks swim!\n" ;
    }
};

I have also created classes that implement the interfaces:

class Quack: public QuackBehavior
{
    void quack()
    {
        std::cout << "QUACK!\n" ;
    }
};

class FlyWithWings: public FlyBehavior
{
    void fly()
    {
        std::cout << "I'm flying...\n" ;
    }
};

and likewise. I created a class inheriting the Duck class and my main method:

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

    void display()
    {
        std::cout << "I'm a real duck\n" ;
    }
};

int main(int argc, char const *argv[])
{
    Duck mallard = new MallardDuck() ;
    mallard.performFly() ;
    mallard.performQuack() ;
    return 0;
}

However, when I am compiling the program, I am getting a long list of errors. Can someone help me with this? Thanks in advance to people who actually read the complete problem.

5 Answers 5

2

FlyBehavior/QuackBehavior are abstract classes, you can't make them members of Duck, you have to use pointer instead(dynamic polymorphism dispatches through reference or pointer):

#include <memory>

class Duck
{
public:
    std::unique<FlyBehavior> flyBehavior;
    std::unique<QuackBehavior> quackBehavior;
//...
};


MallardDuck() : flyBehavior( new FlyWithWings()), quackBehavior(new Quack()) 
{ }

As FlyBehavior/QuackBehavior serve as abstract classes, you should make their destructor virtual.

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

class FlyBehavior
{
public:
    virtual void fly() = 0 ;
    virtual ~FlyBehavior() {}
};
Sign up to request clarification or add additional context in comments.

2 Comments

Why on earth would you suggest using smart pointers to someone who doesn't know raw pointers?
@icepack: because this way you can avoid touching on all the subtleties of pointers. There are two schools of thought on how to teach C++: either as C and then ++ or as a brand new language. The brand new language school makes use of the Standard Library early on, and delve into the deepest corners afterward.
1

Don't forget to implement pure virtual method:

virtual void quack() = 0 ;

 

When you declare an object normally, you can not new it. And when you declare it as a pointer you have to call its items by ->.

QuackBehavior quackBehavior;
quackBehavior = new Quack() ;  // <------- ERROR, quackBehavior is not a pointer

and

Duck mallard = new MallardDuck(); // <------- ERROR, mallard is not a pointer
mallard.performFly() ; // <-------- ERROR, you must use -> instead of .
                       //           if mallard is a pointer

Finally, use this code:

class MallardDuck: public Duck
{
public:
    MallardDuck()
    {
    }

    void display()
    {
        std::cout << "I'm a real duck\n" ;
    }
};

int main(int argc, char const *argv[])
{
    Duck *mallard = new MallardDuck() ;
    mallard->performFly() ;
    mallard->performQuack() ;

    ...

    delete mallard;
}

You're learning C++, after understanding pointers, it's good to know and use smart-pointers(std::unique_ptr, std::shared_ptr) instead of bare pointers.

2 Comments

I'd say if he's just learning C++ he's better off not using smart pointers. He has to learn how pointers really work at some point. He'll have a better understanding of them if he uses them without crutches at first, and then moves on to using smart pointers where applicable later. He'll then also have a better understanding of how smart pointers work, where they don't work, and their limitations than if he doesn't get practice using normal pointers at all.
Yes I have implemented the pure virtual function in my class. And the code is working fine now. Excellent way of helping me understand the concepts! :)
1

You can not have an instance of an abstract class. You should have pointers to the base class instead of objects in Duck, otherwise you will get compilation errors.

It is also apparent from this calls:

quackBehavior = new Quack();
flyBehavior = new FlyWithWings(); 

new Quack() and new FlyWithWings() both return pointers.

Comments

1

In class Duck, abstract class member objects flyBehavior and quackBehavior needs to be instantiated with their derived classes FlyWithWings and Quack in the constructor, meanwhile the members needs to be of type pointer to use such an inheritance scheme:

class Duck
{
public:
    FlyBehavior* flyBehavior;
    QuackBehavior* quackBehavior;
    Duck()
    {
          flyBehavior = new FlyWithWings();
          quackBehavior = new Quack();
    }

    ~Duck()
    {
          delete flyBehavior;
          delete quackBehavior;
    }

    virtual void display() = 0 ;
    void performQuack()
    {
        quackBehavior.quack() ;
    }

    void performFly()
    {
        flyBehavior.fly() ;
    }

    void swim()
    {
        std::cout << "All ducks swim!\n" ;
    }
};

You'd also need virtual destructors in the base classes:

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

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

};

1 Comment

actually i don't want to initialize the flyBehavior and quackBehavior in the Duck class. I want to initialize them in the MallardDuck class.
0

By declaring a function as pure virtual like this:

virtual void display() = 0 ;

, you're effectively making the class it belongs to, abstract. Abstract means it can never be instantiated. You can never create instances of type of abstract class. Get rid of = 0 if you want to be able to have Duck objects.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.