如何在c++11中实现工厂+装饰器模式
How to implement factory+decorator pattern in c++11
我决定将study/translate 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;
}
这段代码主要做的是;有两个派生类A
和B
;它们每个都有一个成员函数,显示调用了哪一个。还有一个名为 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
看起来问题出在 CountingFactory
中的 unique_ptr
。我的理解是用于初始化装饰对象的指针被释放,它会导致未定义的行为(clang 情况)或终止(gcc 情况)。
因此,我决定使用原始指针并添加(上面注释掉的)行:
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
s 替换 unique_ptr
s,但没有用,它没有用。
我还能通过不同的方法摆脱智能指针吗?或者我必须手动管理我在工厂内部分配的内存(不推荐)?
崩溃的原因是你只是通过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。
据我了解,您需要 FooDecorator
才能取得 pBase
的所有权。您可以通过更改
来实现此目的
AbstractBase *mpBase;
到
std::unique_ptr<AbstractBase> mpBase;
所以你在 CountingFactory
中创建 FooDecorator
像这样:
return std::unique_ptr<AbstractBase>(new FooDecorator(new A()));
或者在 C++14 中:
return std::make_unique<FooDecorator>(new A());
我决定将study/translate 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;
}
这段代码主要做的是;有两个派生类A
和B
;它们每个都有一个成员函数,显示调用了哪一个。还有一个名为 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
看起来问题出在 CountingFactory
中的 unique_ptr
。我的理解是用于初始化装饰对象的指针被释放,它会导致未定义的行为(clang 情况)或终止(gcc 情况)。
因此,我决定使用原始指针并添加(上面注释掉的)行:
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
s 替换 unique_ptr
s,但没有用,它没有用。
我还能通过不同的方法摆脱智能指针吗?或者我必须手动管理我在工厂内部分配的内存(不推荐)?
崩溃的原因是你只是通过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。
据我了解,您需要 FooDecorator
才能取得 pBase
的所有权。您可以通过更改
AbstractBase *mpBase;
到
std::unique_ptr<AbstractBase> mpBase;
所以你在 CountingFactory
中创建 FooDecorator
像这样:
return std::unique_ptr<AbstractBase>(new FooDecorator(new A()));
或者在 C++14 中:
return std::make_unique<FooDecorator>(new A());