【问题标题】:Problems with implementing Interfaces in C++在 C++ 中实现接口的问题
【发布时间】:2013-07-30 03:44:54
【问题描述】:

我正在尝试使用 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;
}

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

【问题讨论】:

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


    【解决方案1】:

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

    从这个调用中也很明显:

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

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

    【讨论】:

      【解决方案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() {}
      };
      

      【讨论】:

      • 为什么你会建议对不知道原始指针的人使用智能指针?
      • @icepack:因为这样可以避免触及指针的所有细微之处。关于如何教授 C++ 有两种思想流派:要么作为 C 然后 ++,要么作为一种全新的语言。全新的语言学校在早期使用标准库,然后深入研究最深的角落。
      【解决方案3】:

      别忘了实现纯虚方法:

      virtual void quack() = 0 ;
      

       

      当你正常声明一个对象时,你不能new它。当您将其声明为指针时,您必须通过 -&gt; 调用其项目。

      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_ptr, std::shared_ptr)而不是裸指针。

      【讨论】:

      • 我会说如果他只是在学习 C++,他最好不要使用智能指针。他必须了解指针在某些时候是如何真正起作用的。如果他首先在没有拐杖的情况下使用它们,他将对它们有更好的理解,然后在以后适用的情况下继续使用智能指针。与根本不练习使用普通指针相比,他还将更好地了解智能指针的工作原理、不工作的地方以及它们的局限性。
      • 是的,我在课堂上实现了纯虚函数。并且代码现在工作正常。帮助我理解概念的绝佳方式! :)
      【解决方案4】:

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

      virtual void display() = 0 ;
      

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

        • 实际上我不想在Duck 类中初始化flyBehaviorquackBehavior。我想在MallardDuck 类中初始化它们。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-08-01
        • 1970-01-01
        • 2011-03-19
        • 1970-01-01
        • 1970-01-01
        • 2012-02-01
        相关资源
        最近更新 更多