2

我正在尝试使用 C++ 学习设计模式。我正在执行OReilly's Head First Design Patterns关于鸭子问题的第一章中给出的程序。请耐心等待,这是一个很长的问题。

无论如何,我尝试创建以下 2 个接口:

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

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

现在我有一个 Duck 类,它需要具有上述 2 个类的瞬间。我正在做的是:

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" ;
    }
};

我还创建了实现接口的类:

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

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

同样。我创建了一个继承 Duck 类和我的 main 方法的类:

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;
}

但是,当我编译程序时,我得到一长串错误。有人可以帮我弄这个吗?提前感谢那些真正阅读完整问题的人。

4

5 回答 5

2

FlyBehavior/QuackBehavior是抽象类,你不能让它们成为 的成员Duck,你必须使用指针来代替(动态多态性通过引用或指针调度):

#include <memory>

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


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

作为FlyBehavior/QuackBehavior抽象类,您应该将它们的析构函数设为虚拟。

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

class FlyBehavior
{
public:
    virtual void fly() = 0 ;
    virtual ~FlyBehavior() {}
};
于 2013-07-30T06:18:26.703 回答
1

您不能拥有抽象类的实例。你应该有指向基类的指针而不是 中的对象Duck,否则你会得到编译错误。

从这个调用中也可以看出:

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

new Quack()并且new FlyWithWings()都返回指针。

于 2013-07-30T06:16:51.553 回答
1

不要忘记实现纯虚方法:

virtual void quack() = 0 ;

 

当你正常声明一个对象时,你不能new它。当您将其声明为指针时,您必须通过->.

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

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

最后,使用以下代码:

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;
}

您正在学习 C++,在了解指针之后,最好了解和使用智能指针(std::unique_ptrstd::shared_ptr)而不是裸指针。

于 2013-07-30T06:18:30.367 回答
1

在 classDuck中,抽象类成员对象需要用它们的派生类flyBehavior 和构造函数实例化,同时成员需要是指针类型才能使用这样的继承方案:quackBehaviorFlyWithWingsQuack

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" ;
    }
};

您还需要基类中的虚拟析构函数:

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

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

};
于 2013-07-30T06:22:47.220 回答
0

通过像这样将函数声明为纯虚拟函数:

virtual void display() = 0 ;

,您实际上是在将其所属的类抽象化。抽象意味着它永远不能被实例化。您永远不能创建抽象类类型的实例。如果您希望能够拥有 Duck 对象,请摆脱 = 0。

于 2013-07-30T06:21:35.480 回答