2015-01-14 61 views
0

我決定研究/將Head First Design Patterns的Java代碼翻譯爲C++ 11,並且我能夠使用自動內存管理實現大多數模式,這要歸功於聰明的指針。但是,我遇到了一個例子的問題。這裏是我的代碼:如何在C++中實現工廠+裝飾器模式11

#include <iostream> 
#include <memory> 

class AbstractBase { 
public: 
    virtual void foo() = 0; 
    virtual ~AbstractBase() = default; 
}; 

class A : public AbstractBase { 
public: 
    void foo() override { std::cout << "Class A: foo() called" << std::endl; } 
}; 

class B : public AbstractBase { 
public: 
    void foo() override { std::cout << "Class B: foo() called" << std::endl; } 
}; 

class FooDecorator : public AbstractBase { 
public: 
    FooDecorator(AbstractBase *pBase): mpBase(pBase) { } 
    void foo() override 
    { 
     mpBase->foo(); 
     ++mNumberOfFooCalls; 
    } 
    static int getFooCalls() { return mNumberOfFooCalls; } 

private: 
    static int mNumberOfFooCalls; 
    AbstractBase *mpBase; 
}; 

class AbstractFactory { 
public: 
    virtual std::unique_ptr<AbstractBase> createA() = 0; 
    virtual std::unique_ptr<AbstractBase> createB() = 0; 
    virtual ~AbstractFactory() = default; 
}; 

class CountingFactory : public AbstractFactory { 
public: 
    std::unique_ptr<AbstractBase> createA() 
    { 
     // auto pA = new A(); 
     // return std::unique_ptr<AbstractBase>(new FooDecorator(pA)); 
     std::unique_ptr<AbstractBase> pA(new A()); 
     return std::unique_ptr<AbstractBase>(new FooDecorator(pA.get())); 
    } 

    std::unique_ptr<AbstractBase> createB() 
    { 
     // auto pB = new B(); 
     // return std::unique_ptr<AbstractBase>(new FooDecorator(pB)); 
     std::unique_ptr<AbstractBase> pB(new B()); 
     return std::unique_ptr<AbstractBase>(new FooDecorator(pB.get())); 
    } 
}; 

int FooDecorator::mNumberOfFooCalls = 0; 

int main() 
{ 
    std::unique_ptr<AbstractFactory> pFactory(new CountingFactory()); 
    std::unique_ptr<AbstractBase> pObjA = pFactory->createA(); 
    std::unique_ptr<AbstractBase> pObjB = pFactory->createB(); 
    pObjA->foo(); 
    pObjB->foo(); 
    std::cout << "Foo called " << FooDecorator::getFooCalls() 
       << " times." << std::endl; 
} 

這段代碼基本上做了什麼;有兩個派生類AB;他們每個人都有一個單一的成員函數來顯示哪一個被調用。還有一個名爲FooDecorator的裝飾器,它增加了對撥打foo()進行計數的能力。

除了這些,還有CountingFactory這是用來直接獲得裝飾對象。

在使用這個工廠的主要部分,我創建了一個A的實例和一個B的實例。然後分別撥打foo()

當我使用鐺3.5編譯這段代碼並運行它,我沒有得到任何錯誤,但結果有點不同比預期的,因爲它要求B::foo()兩次:

Class B: foo() called 
Class B: foo() called 
Foo called 2 times. 

。另一方面,當我用gcc 4.9.2編譯代碼並運行它,我得到以下錯誤:

pure virtual method called 
terminate called without an active exception 

它看起來像問題是CountingFactoryunique_ptr秒。我的理解是用於初始化裝飾對象的指針被釋放,並導致未定義的行爲(clang case)或終止(gcc case)。

因此,我決定使用原始指針,並添加(以上註釋掉)行:

auto pA = new A(); 
    return std::unique_ptr<AbstractBase>(new FooDecorator(pA)); 

    auto pB = new B(); 
    return std::unique_ptr<AbstractBase>(new FooDecorator(pB)); 

這樣做,事情順利的工作,我從兩種編譯器的預期輸出。但是,現在存在內存泄漏,並且必須刪除分配。

幾乎總是發現一個解決方案,以智能指針來解決這些問題,我正在努力想出解決這個問題的最佳方法。我也嘗試用shared_ptr代替unique_ptr s,但無濟於事,它不起作用。

我能否繼續使用不同方法的智能指針?或者我必須手動管理我在工廠內分配的內存(不是首選)?

+0

@IrrationalPerson有趣,我g以上結果。可能是因爲我的蘋果叮噹3.5。 – mty

回答

2

據我瞭解,你需要FooDecorator採取的pBase所有權。

return std::unique_ptr<AbstractBase>(new FooDecorator(new A())); 

還是在C++ 14:您可以通過更改

AbstractBase *mpBase; 

std::unique_ptr<AbstractBase> mpBase; 

所以你在CountingFactory創建FooDecorator像這樣實現這一

return std::make_unique<FooDecorator>(new A()); 
+0

我試圖在沒有分配但在這種情況下失敗的地方堅持使用原始指針。所以,這個教訓可能更多的是使用智能指針。非常感謝你。 – mty

+0

這實際上有用! –

1

崩潰的原因是您只需通過get方法分配內部指針。

std::unique_ptr<AbstractBase> pB(new B()); 
return std::unique_ptr<AbstractBase>(new FooDecorator(pB.get())); 

這意味着當範圍結束時,將存儲器內的B(或A)是得到delete d。 你可以做的是改爲撥打release

但是爲了避免泄漏,你應該在你的FooDecorator中有一個unique_ptr。

Live on IdeOne

+0

這是否解決了這個問題?如果確實如此,我們可以看到已編譯的代碼 –

+0

這應該運行,但是又將「指向」用戶的指針「刪除」。 – mty