2014-10-29 87 views
2

試圖在C++中使用多態性讓我的腦袋變得圓滿。下面是兩個基本抽象類,DuckFlyingBehavior,以及一系列繼承類(這是基於第一章設計模式)的第一章。C++中的多態性和類抽象示例

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

} 

使用上面的代碼中,我得到以下輸出

Swoop Flying! 
Can't Fly! 
Can't Fly! 

當我期待

Swoop Flying! 
Can't Fly! 
No Flying Set! 

我是不是接近這個例子中,正確的方式(用在Java中這樣做) ?不禁覺得我失去了一些根本性的東西。我試圖理解你如何從類中提取行爲,將其放入另一個類中,然後使用多態性委託給正確的行爲。有沒有更好的方法來解決上述問題?

嗯,或許你在這裏使用多重繼承呢?

回答

2

如果更改

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

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

+0

噢,當然是!在更一般的說明中,這種使用C++中的典型多態和委託?我對Java很有用,所以我可能會試圖以一種不適合C++的方式來實現它。真的很感激任何簡短的想法。 – 2014-10-29 20:08:23

+0

@JamesB我會說這很好,因爲在C++中有很多方法可以做同樣的事情,並且選擇使用哪一種方法。 – kraskevich 2014-10-29 20:14:03

1

首先,您的代碼有沒有抽象基礎類。抽象基類具有純粹的virtual成員函數(如virtual fly() const=0)。 FlyBehavior是一個多態類,但不是抽象的,因爲它的虛函數不是純虛函數。 Duck甚至不是一個多態類(沒有虛擬成員方法)。其次,任何多態類都應該有一個virtual析構函數,這樣任何派生類型的對象都可以從指向多態基的指針中刪除。

接下來,派生鴨子的數據成員比實際使用的要多。例如,MallardDuck具有CantFlyFlySwoopFlyBehaviour*。這可以通過在堆上分配實際的FlyBehaviour並通過智能指針進行管理來避免。 (這個簡單的例子可能不是問題,但只要這些對象變大就會成爲問題。)

最後,成員函數setFlyBehavior()向公衆公開,允許用戶更改FlyBehavior - 你真的想要嗎?

一種可能的設計是如下

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

通常,它是用於preferrable到FlyBehavior是抽象的。如上

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可以只用protected構造(除了移動&拷貝)來實現。區別在於您無法創建Duck對象,但只能創建一個派生的Duck類型。這兩種設計中哪一種最適合取決於應用。

+0

非常感謝Walter。我通過你的例子瞭解了很多,並且首次介紹了獨特的指針。 – 2014-10-30 10:02:22