首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++中的多态性和类抽象示例

C++中的多态性和类抽象示例
EN

Stack Overflow用户
提问于 2014-10-29 19:44:19
回答 2查看 347关注 0票数 2

试图使用C++中的多态性来使我的头脑清醒。下面是两个基本的抽象类,DuckFlyingBehavior,以及一系列继承的类(这是基于Head first Design Patterns的第一章)。

代码语言:javascript
复制
// Define an abstract fly behaviour class
class FlyBehavior {
public:
    virtual void fly() { cout << "No Flying Set!" << endl; }
};

class FlySwoop : public FlyBehavior {
public:
    void fly() { cout << "Swoop Flying!" << endl; }
};

class CantFly : public FlyBehavior {
public:
    void fly() { cout << "Can't Fly!" << endl; }
};

// Define an abstract Duck class
class Duck {
    CantFly nf;
    FlyBehavior *flyBehavior;
public:     
    Duck() { flyBehavior = &nf; }
    void goFly() { flyBehavior->fly(); }
    void setFlyBehavior(FlyBehavior *fb) { flyBehavior = fb; }
};

// Define a new Mallard Duck class
class MallardDuck : public Duck {
    FlySwoop fb;
public:
    MallardDuck(){ setFlyBehavior(&fb); }
};

// Define a new Rubber Duck class
class RubberDuck : public Duck {
    CantFly fb;
public:
    RubberDuck(){ setFlyBehavior(&fb); }
};

// Define a new Toilet Duck Class
class ToiletDuck : public Duck {};

int main(void) {

    Duck *p;
    MallardDuck mallardDuck;
    RubberDuck rubberDuck;
    ToiletDuck toiletDuck;
    p = &mallardDuck;
    p->goFly();
    p = &rubberDuck;
    p->goFly();
    p = &toiletDuck;
    p->goFly();

}

使用上面的代码,我得到以下输出

代码语言:javascript
复制
Swoop Flying!
Can't Fly!
Can't Fly!

当我期待

代码语言:javascript
复制
Swoop Flying!
Can't Fly!
No Flying Set!

我是否以正确的方式处理此示例(习惯于使用Java)?不禁觉得我错过了一些最基本的东西。我试图了解如何从类中提取行为,将其放入另一个类,然后使用多态性将其委托给正确的行为。是否有更好的方法来处理上述问题?

嗯,也许这是你使用多重继承的地方吗?

EN

回答 2

Stack Overflow用户

发布于 2014-10-29 19:58:49

如果你改变了

代码语言:javascript
复制
class Duck {
    CantFly nf;
    FlyBehavior *flyBehavior;
public:     
    Duck() { flyBehavior = &nf; }
    void goFly() { flyBehavior->fly(); }
    void setFlyBehavior(FlyBehavior *fb) { flyBehavior = fb; }
};

代码语言:javascript
复制
class Duck {
    FlyBehavior nf;
    FlyBehavior *flyBehavior;
public:     
    Duck() { flyBehavior = &nf; }
    void goFly() { flyBehavior->fly(); }
    void setFlyBehavior(FlyBehavior *fb) { flyBehavior = fb; }
};

您的代码将产生所需的输出。

在当前版本的代码中,ToiletDuck编译器生成的默认构造函数调用Duck类的默认构造函数,该构造函数将nf设置为指向CantFly类的实例。当然,它会打印Can't fly

票数 2
EN

Stack Overflow用户

发布于 2014-10-29 22:19:10

首先,您的代码没有抽象的基类类。抽象基类是具有纯virtual成员函数(如virtual fly() const=0)的基类。FlyBehavior是一个多态类,但不是抽象类,因为它的虚拟函数不是纯虚拟的。Duck甚至不是多态类(没有虚拟成员方法)。

其次,任何多态类都应该有一个virtual析构函数,这样派生类型的任何对象都可以从指向多态基的指针中删除。

接下来,派生鸭子拥有比实际使用的更多的数据成员。例如,MallardDuck有一个CantFly、一个FlySwoop和一个FlyBehaviour*。可以通过在堆上分配实际的FlyBehaviour并通过智能指针管理它来避免这种情况。(这可能不是这个简单示例的问题,但一旦这些对象变大,就会成为一个问题。)

最后,成员函数setFlyBehavior()向公众公开,允许用户更改FlyBehavior --您真的想要这样吗?

可能的设计如下

代码语言:javascript
复制
struct FlyBehavior    // polymorphic class
{
  virtual void fly() const { cout << "No Flying Set!" << endl; }
  virtual~FlyBehavior() {}
};

struct FlySwoop : FlyBehavior
{
  void fly() const { cout << "Swoop Flying!" << endl; }
};

struct CantFly : FlyBehavior
{
  void fly() const { cout << "Can't Fly!" << endl; }
};

class Duck        // non-polymorphic, but using polymorphism through member
{
  std::unique_ptr<FlyBehavior> flyBehavior; // calls FlyBehavior::~FlyBehavior at destruction
protected:
  explicit Duck(FlyBehavior*f) : flyBehavior(f) { assert(f); }
public:     
  Duck() : flyBehavior(new FlyBehavior) {}  // note: not CantFly as in your code
  Duck(Duck&&) = default;                   // allow move (but no copy)
  Duck&operator=(Duck&&) = default;
  void goFly() const { flyBehavior->fly(); }
};

struct MallardDuck : Duck
{
  MallardDuck() : Duck(new FlySwoop) {}
};

struct RubberDuck : Duck
{
  RubberDuck() : Duck(new CantFly) {}
};

通常情况下,FlyBehavior更倾向于抽象。在这种情况下,Duck只能用一个protected构造函数来实现(除了move & copy):

代码语言:javascript
复制
struct FlyBehavior    // polymorphic class
{
  virtual void fly() const=0 ;   // pure virtual
  virtual~FlyBehavior() {}
};

class Duck        // non-polymorphic, but using polymorphism through member
{
  std::unique_ptr<FlyBehavior> flyBehavior; // calls FlyBehavior::~FlyBehavior at destruction
protected:
  explicit Duck(FlyBehavior*f) : flyBehavior(f) { assert(f); }
public:
  Duck() = delete;                          // no default constructor
  Duck(Duck&&) = default;                   // allow move (but no copy)
  Duck&operator=(Duck&&) = default;
  void goFly() const { flyBehavior->fly(); }
};

以及上面所示的其余代码。区别在于您不能创建一个Duck对象,但是只能创建一个派生的Duck类型。这两种设计中哪一种最适合,取决于应用。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26639244

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档