2017-12-28 33 views
2

최근 C++ 개발로 시작했습니다. 나는 다음과 같은 것이 가능한지를 모르고 있기 때문에 내가 해결할 수없는 문제에 봉착했다.C++ 클래스를 숫자로 매핑

숫자와 클래스 사이의 매핑을 만들고 싶습니다.이 매핑은 추상 클래스에서 파생되었습니다.

기본적으로 내가하고 싶은 것은 해당 클래스와 관련된 주어진 숫자를 기반으로 클래스의 새 인스턴스를 만들 수있는 팩토리 메서드를 만드는 것입니다.

나는 다음을 수행 할 수 있음을 알고 ...

Vehicle *Vehicle::from_type(byte type) 
{ 
    switch(type) 
    { 
     case 0x00: return new Bicyle(); 
     case 0x01: return new Car(); 
     ... 
     case 0x10: return new Truck(); 
    } 

    return null; 
} 

...,하지만 난 차라리하지 내가 DRY를 유지하려는있다.

그것은이 일이의 라인을 따라 뭔가를 할 수있는 방법 :

// I know this is incorrect syntax 
const map<byte, class extends Vehicle> VEHICLE_MAPPING = {{0x00, Bicyle}, {0x01, Car}, ..., {0x10, Truck}}; 

Vehicle *Vehicle::from_type(byte type) 
{ 
    return new VEHICLE_MAPPING[type](); 
} 
+0

첫 번째가 DRY를 위반하는 경우 두 번째도 DRY를 위반합니다. 나는 첫 번째 해결책을 고수 할 것입니다. – Fureeish

+0

첫 번째 해결책은 충분히 건조하고 두 번째는 제 지식으로는 불가능합니다. 스마트 포인터에 대해 읽어야한다고했는데, 코드가 오래된 것 같습니다. – papagaga

+0

파생 클래스마다 팩토리 클래스가 필요할 것 같습니다. 다음은지도에서 설정할 수 있습니다. 나는 그것이 당신에게 좋은 생각인지 모른다. 예라고 대답하면 몇 가지 코드를 제공 할 수 있습니다. – BartekPL

답변

2

나는 당신의 접근 방식은 std::map<uint8_t, std::unique_ptr<Vehicle>>의 사용과 함께 일할 수있는 방법을 볼 수 있지만, 문제가 - 당신은되지 않을 것 그지도를 initializer_list으로 초기화 할 수 있습니다. 복사본은이며, 우리 모두가 알고 있듯이 std::unique_ptr은 복사 할 수 없습니다. 비슷한 논리를 사용하는지도를 초기화하기 위해 Vehicle *Vehicle::from_type(byte type)init() 함수를 만들어야합니다.이 함수는 이미 사용자의 기능이있는 경우 무의미합니다.

또한 귀하의 첫 번째 해결 방안이 DRY에 위배됩니다. 실제로 코드의 다른 곳에서 switch 또는 if을 사용하지 않아도되는 것은 사실 올바른 것입니다. 나는 확실히 그것에 충실 할 것이다.

마지막 주 - std::shared_ptr 복사 할 수 있기 때문에이 잘못 shared_ptr의 사용을 나타 내기 때문에 당신이 사용하는 대신 std::map<uint8_t, std::unique_ptr<Vehicle>>std::map<uint8_t, std::shared_ptr<Vehicle>>initializer_list와 함께 초기화는,하지만 난 그 조언을하지 않을 것입니다. 이 솔루션을 사용하는 최종 낙담이 될 그것은 아주 느린 것입니다해야

class Base{ public: virtual ~Base() = default; }; 
class Derived1 : public Base{}; 
class Derived2 : public Base{}; 

class derived_factory{ 
    private: 
     derived_factory(); 
     static inline std::map<uint8_t, std::shared_ptr<Base>> base_map = { 
      {0x00, std::make_shared<Derived1>()}, 
      {0x01, std::make_shared<Derived2>()} 
     }; 
    public: 
     static std::unique_ptr<Base> from_type(uint8_t type) 
     { 
      return std::make_unique<Base>(*base_map[type]); 
     } 
}; 

int main() 
{ 
    auto ptr = derived_factory::from_type(0x00); 
    // ptr is of a type std::unique_ptr<Base> and points to Derived1 object 
} 

추가 참고 : 당신은 어떻게 든 그렇게 강제 느끼는 경우에, 여기에 예입니다. 지도에서 객체를 구성하고 '템플릿으로 만든'복사 예제로 유지하는 것 외에는 아무것도 수행하지 않습니다. 그들은 모두 기본 클래스에서 파생 된 경우 (그 책은 ++ 11-C 사전 비록, 현대 C++ 세부 설계 참조)

+0

이것은 본질적으로 내가 한 것입니다. 고맙습니다. 그러나, 나는 당신의 충고와 다른 사람들을 내 포스트의 코멘트에서 가져 왔고, 나는 처음에 내가 가지고 있었던 것을 고수하기로 결정했다. C++에 대한 지식이 지금까지 나오지 않아서 결론에 도달하게되어'옵션 2 '가 DRY를 거의 위반하지 않는다는 결론을 얻었습니다. 내 질문에 대한 이와 유사한 해결책이 어떻게 느릴 수 있는지 알 수 있습니다. 그럼에도 불구하고 나는 나의 질문에 대한 대답으로 귀하의 게시물을 받아 들였습니다. 그것은 나의 초기 생각이했던 것과 같습니다. –

1

, 당신은 Loki's implementation에서 공장 패턴, 예를 사용할 수 있습니다.

다음은 몇 가지 구체적인 차량을 만들고 벡터에서 그들을두고 한 다음 각각에 drive() 메서드를 호출하여 인쇄

#include <iostream> 
#include <memory> 
#include <vector> 
#include "factory.h" 

struct Vehicle 
{ 
    virtual ~Vehicle() = default; 
    virtual void drive() = 0; 
}; 

struct Car : Vehicle 
{ 
    static constexpr auto ID = 1; 
    void drive() override { std::cout << "Car\n"; } 
}; 

struct Truck : Vehicle 
{ 
    static constexpr auto ID = 2; 
    void drive() override { std::cout << "Truck\n"; } 
}; 

// Create the factory object 
auto g_factory = MyUtil::Factory<std::unique_ptr<Vehicle>, int>{}; 

void RegisterTypesWithFactory() 
{ 
    // We pass in creator functions for each type. Note that these 
    // could be lambdas or some other freestanding function and they 
    // could accept parameters. 
    g_factory.Register(Car::ID, &std::make_unique<Car>); 
    g_factory.Register(Truck::ID, &std::make_unique<Truck>); 
} 

int main() 
{ 
    // Configure the factory 
    // Note: Registration can be done any time, e.g., later based on input 
    // from a file. I do them all at once here for convenience of illustration. 
    RegisterTypesWithFactory(); 

    // Create some objects with the factory 
    auto vehicles = std::vector<std::unique_ptr<Vehicle>>{}; 
    vehicles.emplace_back(g_factory.Create(Car::ID)); 
    vehicles.emplace_back(g_factory.Create(Truck::ID)); 

    // Do something with the objects 
    for(const auto& v : vehicles) 
    { 
     v->drive(); 
    } 
} 

는 :

Car 
Truck 

에서 라이브 실행 참조 Wandbox.