[英]Runtime error implementing Abstract Factory PIMPL Idiom in C++
嘗試在PIMPL慣用法下實現抽象工廠時,嘗試從Factory范圍之外獲取對象時遇到運行時錯誤。 (請參閱Main中注釋為“運行時錯誤”的部分。當從公共類中調用AcquisitionInterface()方法時,會發生這種情況,該方法從實現中調用AcquisitionInterface())。 但是,當在實現類中通過testFactory()函數的AcquisitionInterface()時,不會發生這種情況(請參見“ 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();
}
代碼中的一件壞事是:
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;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.