代码之家  ›  专栏  ›  技术社区  ›  Aedoro

扩展多个类的C++函数参数

  •  0
  • Aedoro  · 技术社区  · 9 年前

    class Base_1 {};
    class Base_2 {};
    
    class A :
        public Base_1,
        public Base_2
    {
    
    };
    
    class Container 
    {
        template<typename T> // where T should extend Base_1 and Base_2
        void Add(T* pObj) {
            elements.push_back(pObj);
        }
    
        std::vector<???> elements; // all elements should extend Base_1 and Base_2
    };
    

    我不想创建一个中间类Base\u 1\u 2,因为这停止了3个基类的工作,其中一些管理器需要其元素具有基类1和2,而另一个管理器需要2和3。

    所以我的问题是,你怎么设计这个?


    “这闻起来像是XY问题”cdhowie

    我可以想象是这样的。所以我将尝试解释“X”问题。

    我有一组类,它们共享很多功能。类似于“加载到gpu”“渲染”“释放gpu内存”“更新”。但并非所有功能都适用于所有类。例如,有些可能没有“渲染”。现在我有一个类,需要存储很多对象,并在调用“render”之前检查“load to gpu”是否已经发生。但是如何实现呢?你如何基于这种功能组合来存储类(这里我可能会再次倾向于“Y”)。


    编辑2:

    与cdhowie组成的替代方案类似(但不是通用的),以下也是一个解决方案?(可能在Add函数中省略is\u base\u)

    class MyWrapper
    {
    public:
    
        template<class T, typename = std::enable_if_t<
            std::is_base_of<Base_1, T>::value && std::is_base_of<Base_2, T>::value>>
            static MyWrapper MakeWrapper(T* pObj)
        {
            return MyWrapper(dynamic_cast<Base_1*>(pObj), dynamic_cast<Base_2*>(pObj));
        }
    
        Base_1* as_base_1;
        Base_2* as_base_2;
    
    private:
    
        MyWrapper(Base_1* p1, Base_2* p2) {
            as_base_1 = p1;
            as_base_2 = p2;
        }
    };
    
    
    class Container
    {
    public:
    
        template<class T>
        void Add(T* pObj) {
            elements.push_back(MyWrapper::MakeWrapper<T>(pObj));
        }
    
        void Update() {
            for (auto& e : elements) {
                e.as_base_1->do_1();
                e.as_base_2->do_2();
            }
        }
    
        std::vector<MyWrapper> elements; // all elements should extend Base_1 and Base_2
    };
    
    
    void test() {
        A* pA = nullptr;
        Container c;
        c.Add(pA);
    }
    
    1 回复  |  直到 9 年前
        1
  •  3
  •   cdhowie    9 年前

    您可以禁用 Add T 不是从这两种类型派生的:

    template<typename T>
    typename std::enable_if<
        std::is_base_of<Base_1, T>::value &&
        std::is_base_of<Base_2, T>::value,
        void
    >::type Add(T* pObj) {
        elements.push_back(pObj);
    }
    

    那么存储在向量中的指针类型没有太大区别, 如果 Base_1 和 Base_2 dynamic_cast 适合你需要的任何类型。所以你可以储存 Base_1 * 或 Base_2 *

    Base_1 指针和一个要存储的指针 指针,这不需要任何一种类型是多态的。

    然而,这似乎是一个需要解决的特别奇怪的问题,您可以考虑从设计中退一步,看看是否有更好的替代解决方案。


    这是不真实的。只需在中间类中使用虚拟继承。


    #include <type_traits>
    #include <tuple>
    
    template <typename, typename...>
    struct is_subtype_of_all : std::true_type {};
    
    template <typename Derived, typename Base, typename... BaseTail>
    struct is_subtype_of_all<Derived, Base, BaseTail...> : std::conditional<
        std::is_base_of<Base, Derived>::value,
        is_subtype_of_all<Derived, BaseTail...>,
        std::false_type
    >::type {};
    
    template <typename...>
    struct type_index;
    
    template <typename T, typename... Tail>
    struct type_index<T, T, Tail...> : std::integral_constant<std::size_t, 0> {};
    
    template <typename T, typename U, typename... Tail>
    struct type_index<T, U, Tail...> : std::integral_constant<std::size_t, 1 + type_index<T, Tail...>::value> {};
    
    template <typename... T>
    class interface_wrapper
    {
    public:
        template <typename U, typename = typename std::enable_if<is_subtype_of_all<U, T...>::value>::type>
        explicit interface_wrapper(U *p)
            : pointers{static_cast<T *>(p)...} {}
    
        template <typename U>
        U * get() const
        {
            return std::get<type_index<U, T...>::value>(pointers);
        }
    
    private:
        std::tuple<T *...> pointers;
    };
    

    现在,你可以存储 interface_wrapper<Base_1, Base_2> 在你的向量中,你可以使用 .get<Base_1>()->some_member_of_Base_1

    此实现不要求对象是多态的。