在C ++中实现接口的问题

时间:2013-07-30 06:13:36

标签: c++ design-patterns inheritance pure-virtual

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

无论如何,我试图创建以下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;
}

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

5 个答案:

答案 0 :(得分: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() {}
};

答案 1 :(得分:1)

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

这一点也很明显:

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

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

答案 2 :(得分: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)而不是简单的指针。

答案 3 :(得分:1)

在类Duck中,抽象类成员对象flyBehaviorquackBehavior需要在构造函数中使用派生类FlyWithWingsQuack进行实例化,同时成员需要是使用这种继承方案的类型指针:

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();

};

答案 4 :(得分:0)

通过将此函数声明为纯虚拟:

virtual void display() = 0 ;

,你正在有效地制作它所属的类,抽象。抽象意味着它永远不会被实例化。您永远不能创建抽象类类型的实例。如果你想能够拥有Duck对象,请摆脱= 0.