Как вызвать функции унаследованного класса в шаблонном классе - PullRequest
1 голос
/ 23 сентября 2019

Если класс наследует несколько классов с одной и той же функцией, как он вызывает функцию каждого унаследованного класса без указания вручную каждого класса?

Пример кода, как показано ниже:

#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.

Ответы [ 3 ]

4 голосов
/ 23 сентября 2019

Если вы не хотите, чтобы какая-либо из баз повторялась (и ни одна из баз не наследовала друг от друга), вы можете сделать это;

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<Interface2>, в свою очередь, имеет Interface2 в качестве базового класса.

Если вы повторяете базы или используете две базы, которые разделяют другую базу, например

ObjectWithTemplate<Interface1, Interface1> object;

ObjectWithTemplate<Interface1, SomethingDerivedFromInterface1> object2;

, тогда код будетне компилируется из-за двусмысленности.

2 голосов
/ 23 сентября 2019

Вдохновленный Создание одного члена класса для каждого аргумента шаблона переменной , использование 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);
    }
};
1 голос
/ 23 сентября 2019

Сложенные выражения из C ++ 17 помогают здесь:

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

Для версии C ++ 11 / C ++ 14 это также можно сделать, но более многословно.

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