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

时间:2019-09-23 03:44:18

标签: c++ templates

如果一个类继承具有相同功能的多个类,那么如何在不手动指定每个类的情况下调用每个继承的类的功能呢?

示例代码如下:

#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的{​​{1}},考虑到会有foo(),{{1},我该如何编写代码来调用每个继承的接口的foo() }。

3 个答案:

答案 0 :(得分:4)

假设您不希望重复任何碱基(并且没有碱基彼此继承),则可以执行此操作;

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;

实际上具有Interface1ObjectWithTemplate<Interface2>作为基类。 ObjectWithTemplate<Interface2>依次将Interface2作为基类。

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

ObjectWithTemplate<Interface1, Interface1> object;

ObjectWithTemplate<Interface1, SomethingDerivedFromInterface1> object2;

然后,由于歧义,代码将无法编译。

答案 1 :(得分:2)

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

答案 2 :(得分:1)

C ++ 17的

Folding expressions在这里有帮助:

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

对于C ++ 11 / C ++ 14版本,它也可以完成,但是比较冗长。