当尝试在PIMPL习惯下实现抽象工厂时,我在尝试从Factory范围外获取对象时遇到运行时错误。 (参见"运行时错误"在Main中注释的部分。当从公共类调用acquireInterface()方法时会发生这种情况,该公共类从实现中调用acquireInterface())。 但是,当实现类中的testFactory()函数中的acquireInterface()时,这不会发生(参见" 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_ */
---文件:Factory.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
---文件:FactoryImpl.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();
}
答案 0 :(得分:1)
您的代码中有一件坏事:
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;