如何在c ++ 11中实现工厂+装饰模式

时间:2015-01-14 07:45:10

标签: c++ c++11 design-patterns stl smart-pointers

我决定学习/翻译Head First Design Patterns' Java代码到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()

当我使用clang 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

看起来问题是unique_ptr内的CountingFactory。我的理解是用于初始化装饰对象的指针被释放,导致未定义的行为(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));

这样做,事情成功,我得到了两个编译器的预期输出。但是,现在存在内存泄漏,必须删除分配。

几乎总能找到一个解决这些问题的智能指针的解决方案,我正在努力想出这个问题的最佳方法。我也尝试用unique_ptr替换shared_ptr s,但无济于事,它无效。

我可以按照不同的方法逃脱智能指针吗?或者我是否必须手动管理我在工厂内分配的内存(不是首选)?

2 个答案:

答案 0 :(得分:2)

据我了解,您需要FooDecorator获取pBase的所有权。您可以通过更改

来实现此目的
AbstractBase *mpBase;

std::unique_ptr<AbstractBase> mpBase;

所以你在FooDecorator中创建CountingFactory就像这样:

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

或者在C ++ 14中:

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

答案 1 :(得分: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