클래스가 Image
인 것으로 가정합니다. 파싱 중 어떤 시점에서 적절한 시간에 "Image"가 읽혀집니다. 즉, 클래스 Image
의 객체를 만들고 싶습니다.문자열을 기반으로 객체 생성
내가 고려중인 것은이 문자열을 생성자 호출에 적절한 클래스로 매핑하는 것이지만이를 수행하는 방법을 잘 모르겠습니다.
e.e.
container.push_back(some_map[stringParsedIn]); // basic idea
클래스가 Image
인 것으로 가정합니다. 파싱 중 어떤 시점에서 적절한 시간에 "Image"가 읽혀집니다. 즉, 클래스 Image
의 객체를 만들고 싶습니다.문자열을 기반으로 객체 생성
내가 고려중인 것은이 문자열을 생성자 호출에 적절한 클래스로 매핑하는 것이지만이를 수행하는 방법을 잘 모르겠습니다.
e.e.
container.push_back(some_map[stringParsedIn]); // basic idea
당신은 공장 기능을 설명하고 있습니다. 레지스트리에서 간단한 if/else
체인까지 여러 가지 방법으로이를 수행 할 수 있습니다.
일반적으로 Image
클래스는 다른 "파싱 된"유형과 비슷한 기본 클래스에서 파생됩니다. 그렇게하면 같은 컨테이너에 모두 추가 할 수 있습니다. 당신은 일반적으로 매크로를 사용하는 것이 CreateMedia
대신, 공장을
Media *CreateMedia(const string &type) {
if (type == "Image") {
return new Image;
} else if (type == "Sound") {
return new Sound;
} else {
// handle invalid type error
}
}
또 다른 대안은 레지스트리를 사용하는 것입니다
class Media {
public:
virtual Save() = 0;
};
class Image : public Media {
public:
Image() { }
virtual Save() { ... }
};
class Sound : public Media {
public:
Sound() { }
virtual Save() { ... }
};
가장 간단한 구조는 공장 기능은 다음과 같습니다
이 계층 구조를 상상/레지스트리 및 하위 메커니즘을 만드는 몇 가지 메커니즘 :
// This is some mechanism to create types of Media.
template <typename T>
struct CreatorFunction {
Media *operator() {
return new T;
}
};
// This is the factory that the types will register with.
class Factory {
public:
// singleton access function.
static Factory* Get() {
static Factory* f = new Factory;
return f;
}
// Creates Media of the given type.
Media* Create(const string& name) { return registry_[name](); }
// Records 'name' with the creator function 'func'.
void Add(const string& name, const CreatorFunction &func) {
registry_.insert(name, func);
}
private:
Factory() { } // users can't create factories, they can only use singleton.
hash_map<string, CreatorFunction> registry_;
};
#define REGISTER_MEDIA(type) Factory::Get()->Add(#type, CreatorFunction<type>);
REGISTER_MEDIA(Image); // usually goes with the Image class.
REGISTER_MEDIA(Sound); // usually goes with the Sound class.
int main(int argc, char** argv) {
string parsedIn = "Image";
Factory::Get()->Create(parsedIn);
}
이것은 전반적으로보다 깔끔한 접근법이지만 링커가 심볼이 사용되지 않는다고 생각하고 바이너리에서 등록 된 중요한 클래스를 트리밍하는 데 문제가있을 수 있습니다. 더 복잡한 것을 필요로 할 때까지 if/then
체인을 계속 사용하고 싶을 것입니다. 모든 하위 유형이 정의 된 단일 위치를 갖는 것이 불가능하면 일반적으로 레지스트리로 이동합니다.
즉
Image *createImage() {
return new Image();
}
그런 다음지도에서이 함수에 대한 포인터를 저장할 수, 당신은 생성자로 함수 포인터를 저장할 수 없습니다,하지만 당신은 새롭게 구축 된 객체를 반환하는 함수에 대한 포인터를 저장할 수 .
std::map<std::string, Image *(*)()> constructorMap;
constructorMap.insert(std::pair<std::string, Image *(*)()>("Image", createImage));
그리고 내가 100 % 당신이 요구하고있는 무슨
Image *myImage = constructorMap["Image"]();
로 부르지 만, 나는 그것을 추측을 줄 것이다.
Image* makeImage(ArgType arg) { return new Image(arg); }
을 그리고 당신은 당신의지도에 함수 포인터를 저장할 수 있습니다 :
당신은 기능의 생성자를 포장 할 수!
map["Image"] = makeImage;
나중에 전화 해주세요.
SuperclassOfImage soup = map["Image"](arg);
물론 여기에 제한은 함수의 타입 서명이 동일한 유형의 인수를해야하며 동일한 유형 (이미지 또는 이미지의 부모 중 하나는 클래스의 인스턴스)을 반환해야한다는 것입니다.
Stephen이 지적한 것처럼 Factory 패턴 (Image는 추상 기본 클래스라고 가정)을 설명합니다. 그러나 if/else 문으로 구성된 커다란 함수 대신 설명 된대로 문자열을 작성 함수와 연관시키는 것이 도움이 될 수 있습니다. 이미지 하위 클래스를 모두 같은 방식으로 구성 할 수 있다고 가정하면 다음과 같은 한 가지 방법을 사용할 수 있습니다.
typedef Image* create_image_function();
template <class T>
Image* create_image(SomeType arg)
{
return new T(arg);
}
...
map<string, create_image_function*> creators;
creators["Foo"] = &create_image<Foo>;
creators["Bar"] = &create_image<Bar>;
creators["Baz"] = &create_image<Baz>;
shared_ptr<Image> ImageFactory::make_image(const string& str)
{
// checking to see if str exists as a key
// would be nice
return shared_ptr<Image>(creators[str](arg));
}
이 질문의 구문 분석에 문제가 있습니다. –
가능한 복제본 [해당 클래스 이름을 포함하는 문자열에서 개체를 인스턴스화하는 방법이 있습니까?] (http://stackoverflow.com/questions/582331/is-there-a-way-to-instantiate-objects-from- a-string-holding-their-class-name) – hadley