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

如何在模板类中调用继承类的函数

  •  0
  • Mine  · 技术社区  · 7 年前

    如果一个类用同一个函数继承多个类,它如何调用每个继承类的函数而不手动指定每个类?

    示例代码如下所示:

    #include <cstdio>
    
    class Interface1
    {
      public:
        virtual ~Interface1() = default;
        void foo()
        {
            printf("%s\n", __PRETTY_FUNCTION__);
        }
    };
    
    class Interface2
    {
      public:
        virtual ~Interface2() = default;
        void foo()
        {
            printf("%s\n", __PRETTY_FUNCTION__);
        }
    };
    
    class ObjectWithoutTemplate : public Interface1, Interface2
    {
      public:
        void foo()
        {
            // How do I write the code to call each InterfaceX's foo() here
            // without manually specify each class?
            Interface1::foo();
            Interface2::foo();
            // The desired code looke like
            // for each interface in Interfaces {
            //     interface::foo()
            // }
        }
    };
    
    template <class... Interfaces>
    class ObjectWithTemplate : Interfaces...
    {
      public:
        void foo()
        {
            // It does not compile if the template does not inherit Interface[1|2]
            Interface1::foo();
            Interface2::foo();
            // The desired code looke like
            // for each interface in Interfaces {
            //     interface::foo()
            // }
        }
    };
    int main()
    {
        ObjectWithoutTemplate objWithout;
        ObjectWithTemplate<Interface1, Interface2> objWith;
        objWithout.foo();
        objWith.foo();
        return 0;
    }
    

    对于 ObjectWithoutTemplate ,我可以调用 foo() 通过手动指定接口:

        Interface1::foo();
        Interface2::foo();
    

    要不是 ObjectWithTemplate 的 foo() ,如何编写调用每个继承接口的代码 foo() Interface3 , Interface4 也

    0 回复  |  直到 7 年前
        1
  •  4
  •   Peter    7 年前

    假设您不希望任何基重复(并且没有一个基相互继承),您可以这样做;

    template <class FirstInterface, class... Interfaces>
    class ObjectWithTemplate : public FirstInterface, public ObjectWithTemplate<Interfaces...>
    {
       public:
          void foo()
          {
              FirstInterface::foo();
              ObjectWithTemplate<Interfaces...>::foo();
          };
    };
    
    // partial specialisation
    template<class LastInterface> 
    class ObjectWithTemplate<LastInterface> : public LastInterface
    {
        public:
           void foo()
           {
               LastInterface::foo();
           };
    };
    

    类型的对象

    ObjectWithTemplate<Interface1, Interface2> object;
    

    实际上有 Interface1 和 ObjectWithTemplate<Interface2> 作为基类。 ObjectWithTemplate<接口2> Interface2 作为基类。

    如果重复碱基,或使用两个共享另一个碱基的碱基,例如

    ObjectWithTemplate<Interface1, Interface1> object;
    
    ObjectWithTemplate<Interface1, SomethingDerivedFromInterface1> object2;
    

    然后,由于模棱两可,代码将无法编译。

        2
  •  2
  •   Mine    7 年前

    灵感来自 Generating one class member per variadic template argument std::tuple<> 让它工作。

    它不是完美的,因为它增加了二进制大小,但它工作得很干净。

    template <class... Interfaces>
    class ObjectWithTemplate : public Interfaces...
    {
      public:
        std::tuple<Interfaces...> interfaces;
    
        void foo()
        {
            // The size becomes 8 * num-of-inherited-classes
            printf("sizeof(interfaces)=%zu\n", sizeof(interfaces));
            std::apply([&](auto&&... args) {
                (static_cast<decltype(args)>(*this).foo(), ...);
                },
                interfaces);
        }
    };
    
        3
  •  1
  •   Jarod42    7 年前

    Folding expressions 从C++17可以帮助您:

    template <class... Interfaces>
    class ObjectWithTemplate : public Interfaces...
    {
      public:
        void foo()
        {
            (Interfaces::foo(), ...);
        }
    };
    

    对于C++11/C++14版本,也可以这样做,但更详细。