2015-01-14 59 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