Фабрика с экземплярами производных классов - PullRequest
0 голосов
/ 03 апреля 2019

У меня странный вариант использования.Вот очень упрощенная версия.

Допустим, у меня есть класс Base и классы DerivedOne и DerivedTwo, которые являются производными от класса Base.

Тогда,есть перечисление:

enum DerClasses {Derived1, Derived2};

и функция, которая будет принимать перечисление и возвращать экземпляр производного класса, в зависимости от значения.

Что-то вроде:

inline Base* create_instance(DerClasses enum_class){
    switch(enum_class) {
        case Derived1:
            return new Derived1();
        case Derived2:
            return new Derived2();
    }
}

Очевидно, что это работает, но только с последующим приведением к производному классу.

Derived1 *derived_pointer = dynamic_cast<Derived1*>(pointer);

И я не хочу, чтобы пользователи сами делали эти динамические приведения или даже знали что-либо оклассы.

Можно ли как-то скрыть эти приведения и создать API с автоматическим выводом типа, например

auto ptr = create_instance(DerClasses::Derived1);
ptr->derived1_class_only_variable = 123;

Ответы [ 2 ]

3 голосов
/ 03 апреля 2019
template<DerClasses enum_class>
auto create_instance(){
  if constexpr (enum_class == DerClasses::Derived1) {
    return std::make_unique<Derived1>();
  else if constexpr (enum_class == DerClasses::Derived2) {
    return std::make_unique<Derived2>();
}

это похоже на .Делать это в очень раздражает.

Если вы не знаете значение DerClasses во время компиляции, это не работает и не может работать.Самое близкое, что вы можете получить, это стиль передачи продолжения:

template<class F>
decltype(auto) create_instance(DerClasses enum_class, F&& f){
  switch(enum_class) {
    case DerClasses::Derived1:
      return f(std::make_unique<Derived1>());
    case DerClasses::Derived2:
      return f(std::make_unique<Derived2>());
  }
}

, который используется как:

create_instance(DerClasses::Derived1, [&](auto&& ptr) {
  if constexpr( std::is_same< std::decay_t<decltype(*ptr)>, Derived1 >{} )
    ptr->derived1_class_only_variable = 123;
});

, но это тоже отстой, потому что лямбда вызывается с обоими производными типами;запускается только один.

Использование переопределения может сработать, но опять вы сходите с ума.

2 голосов
/ 03 апреля 2019

Вы можете сделать это с помощью некоторого метапрограммирования. Если вы используете C ++ 11/14, вы можете сделать что-то вроде этого:

enum class ClassType {
    FirstType,    
    SecondType,
    ThirdType
};

 namespace internal {

    template <ClassType Type>
    struct _build_type {};

    template <>
    struct _build_type<ClassType::FirstType> {
        constexpr auto operator()() {
            return std::make_unique<MyFirstType>();
        }
    };

    template <>
    struct _build_type<ClassType::SecondType> {
        constexpr auto operator()() {
            return std::make_unique<MySecondType>();
        }
    };

    template <>
    struct _build_type<ClassType::ThirdType> {
        constexpr auto operator()() {
            return std::make_unique<MyThirdType>();
        }
    };

} 

template <WindowType Type>
constexpr auto create_instance() {
    return internal::_build_type<Type>{}();
}

И тогда ваш код становится именно тем, что вы говорите:

auto ptr = create_instance<ClassType::FirstType>();
ptr->derived1_class_only_variable = 123;

В современном C ++ 17 вы можете упростить код с помощью простого условия constexpr if.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...