在C++中实现抽象工厂 PIMPL 习语的运行时错误
Runtime error implementing Abstract Factory PIMPL Idiom in C++
当尝试在 PIMPL 习惯用法下实现抽象工厂时,我在尝试从工厂范围之外获取对象时出现运行时错误。(请参阅在 Main 中注释为"运行时错误"的部分。当从公共类调用 acquireInterface(( 方法时会发生这种情况,该方法从实现调用 acquireInterface((。但是,当从实现类中的testFactory((函数获取Interface((时,不会发生这种情况(请参阅"testFactory(("函数(。有什么建议吗?在启用RTTI的MinGW 4.8和VC++11中尝试。
提前谢谢。
--- 文件: IType.hpp ---
#ifndef ITYPE_HPP_
#define ITYPE_HPP_
class ITYPE {
public:
ITYPE() {
std::cout << "ITYPE()" << std::endl;
};
virtual ~ITYPE(){
std::cout << "~ITYPE()" << std::endl;
};
virtual void hello() = 0;
};
#endif /* ITYPE_HPP_ */
--- 文件: 工厂.hpp ---
#ifndef FACTORY_HPP
#define FACTORY_HPP
#include <memory>
#include <iostream>
#include "IType.hpp"
class Factory {
public:
Factory();
~Factory();
void testFactory();
ITYPE* acquireInterface(const char* type);
private:
class Impl;
std::unique_ptr<Impl> m_pimpl;
};
#endif //FACTORY_HPP
--- 文件:工厂.cpp ---
// Implementations
// ----------------------------------------------------------------------
class ConcreteA : public ITYPE {
public:
ConcreteA(){ std::cout << "ConcreteA()" << std::endl; }
~ConcreteA(){ std::cout << "~ConcreteA()" << std::endl; }
void hello() { std::cout << "A says Hello" << std::endl; }
};
class ConcreteB : public ITYPE {
public:
ConcreteB(){ std::cout << "ConcreteB()" << std::endl; }
~ConcreteB(){ std::cout << "~ConcreteB()" << std::endl; }
void hello() { std::cout << "B says Hello" << std::endl; }
};
// ----------------------------------------------------------------------
template<typename Type> ITYPE* createType()
{
return new Type();
}
/**
* @brief Abstract Factory for ITYPES.
*/
class Factory::Impl {
public:
/**
* @brief Constructor
* @details Implementations to be added here using function addType()
*/
Impl() {
addType<ConcreteA>("A");
addType<ConcreteB>("B");
};
ITYPE* acquireInterface(const char* type)
{
std::cout << "Acquiring interface for " << type << "..." << std::endl;
Impl::map_type::iterator iter = m_map.find(type);
return iter->second();
}
// THIS WORKS
void testFactory()
{
ITYPE* iA = acquireInterface("A");
iA->hello();
delete iA;
ITYPE* iB = acquireInterface("B");
iB->hello();
delete iB;
}
private:
/** @brief Adds a type to the Abstract Factory
* @param componentName short string (no spaces) to identify implementation */
template<typename Type>
void addType(const char* componentName) {
ComponentFactoryFuncPtr function = createType<Type>;
m_map.insert(std::make_pair(componentName, function));
};
public:
/**
* @brief Abstract factory constructor function pointer
*/
typedef ITYPE* (*ComponentFactoryFuncPtr)();
/**
* @brief Type for map holding type identifier / constructor function
*/
typedef std::map<const char*, ComponentFactoryFuncPtr> map_type;
private:
map_type m_map; /**< map holding type identifier / constructor function */
};
Factory::Factory() : m_pimpl(new Impl()) { }
Factory::~Factory() { }
void Factory::testFactory()
{
m_pimpl->testFactory();
}
ITYPE* Factory::acquireInterface(const char* type)
{
return m_pimpl->acquireInterface(type);
}
---主要---
#include <iostream>
#include <memory>
using namespace std;
#include "Factory.hpp"
int main()
{
{
Factory f;
// OK
std::cout << "This works:" << std::endl;
f.testFactory();
// Runtime error (acquireInterface("A") returns NULL ptr)
ITYPE* iA = f.acquireInterface("A");
iA->hello();
delete iA;
ITYPE* iB = f.acquireInterface("B");
iB->hello();
delete iB;
}
return getchar();
}
代码中的一个坏事是:
typedef std::map<const char*, ComponentFactoryFuncPtr> map_type;
主要问题是,即使文本相同,也无法保证const char*
文本具有相同的地址。
您的代码会尝试此操作:
ITYPE* iA = f.acquireInterface("A");
无法保证字符串文本"A"
的指针值与您设置地图时使用的"A"
相同。 因此,行为是不确定将会发生什么的。
如果map
键的目标是有一个字符串,那么使用一个字符串。 您现在可以完全控制键表示的内容,而不是您不知道编译器如何处理字符串文本的const char *
。 你真正知道的是"A"
是一个字符串文字,但这就是你真正能知道的。
修复应该是这样的:
typedef std::map<std::string, ComponentFactoryFuncPtr> map_type;
相关文章:
- 概念可以与 CRTP 习语一起使用吗?
- C++17 pimpl 习语上下文中的自定义迭代器
- pImpl习语-将私有类实现放在cpp中有什么缺点
- 不能使用 pimpl 习语将用户定义的向量插入到封装的向量中
- 指向可配置实现的Pimpl习语
- Pimpl 习语实现取决于模板函数
- 使用std::unique_ptr的C++Pimpl习语不完整类型
- C++中的Pimpl习语和私有构造函数
- 如何在DLL库的公共接口中使用pImpl习语
- 在C++中实现抽象工厂 PIMPL 习语的运行时错误
- 是在实践中真正使用的PIMPL习语
- 使用shared_ptr处理不完全类型的Pimpl习语
- PIMPL 习语的替代方案,当您希望界面拥有所有内存时
- 实现pimpl习语时的链接器错误
- 使用const std::unique_ptr实现pimpl习语
- 在PIMPL习语中使用引用的利弊
- 使用pimpl习语的模板化类不正确
- Pimpl习语和内部对象协作,无需友元声明
- 如何将pimpl习语与Qt和QObject的子类一起使用
- 如何将实现仅公开给pimpl习语中的一组指定的类