带有派生类实例的工厂

时间:2019-04-03 14:46:54

标签: c++ c++11 inheritance design-patterns polymorphism

我有一个奇怪的用例。这是它的非常简化的版本。

假设我有一个Base类和一个DerivedOneDerivedTwo类,它们是从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 个答案:

答案 0 :(得分:3)

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;
});

但是那也很糟糕,因为lambda是用两种派生类型调用的;只运行一次。

使用覆盖可能会起作用,但是您又一次发疯了。

答案 1 :(得分:2)

您可以使用一些元编程来做到这一点。如果您使用的是C ++ 11/14,则可以执行以下操作:

private void populatelistView() {
            final Cursor res = userDb.getAllRows();
            final String[] fromFeildnames = new String[]{ DatabaseUser.KEY_1, DatabaseUser.KEY_2};
            final int[] toViewIds = new int[]{R.id.textViewNum, R.id.textViewItem};
            final SimpleCursorAdapter myCursorAdaptor;
            myCursorAdaptor = new SimpleCursorAdapter(getBaseContext(), R.layout.item_layout, res, fromFeildnames, toViewIds, 0){
                @Override
                public View getView(int position, View convertView, ViewGroup parent) {
                    LayoutInflater inflater = getLayoutInflater();
                    View rowView = inflater.inflate(R.layout.item_layout, null, true);
                    delete= (Button)rowView.findViewById(R.id.deleteItem);
                    delete.setTag(position);


                    Cursor cursor = (Cursor) mylist.getItemAtPosition(position);
                    String listName = cursor.getString(1);
                    String displayName = db.getName(listName);

                    TextView textView = (TextView) rowView.findViewById(R.id.textViewItem);
                    textView.setText(displayName);
View.OnClickListener() {

                        @Override
                        public void onClick(View v) {
                            View parentRow = (View) v.getParent();
                            ListView listView = (ListView) parentRow.getParent();
                            final int position = listView.getPositionForView(parentRow);
                            Cursor cursor = (Cursor) mylist.getItemAtPosition(position);
                            Toast.makeText(getApplicationContext(), "Button " + position, Toast.LENGTH_SHORT).show();
                        }
                    });
                    return rowView;
                }
            };
            mylist.setAdapter(myCursorAdaptor);
        }

然后您的代码就变成了您所说的:

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>{}();
}

在现代C ++ 17中,您可以使用简单的auto ptr = create_instance<ClassType::FirstType>(); ptr->derived1_class_only_variable = 123; 条件来简化代码。