当前位置: 首页 > 知识库问答 >
问题:

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

水渊
2023-03-14

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

示例代码如下:

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

我可以通过手动指定接口来调用接口:

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

但是对于ObjectWithTemplatefoo(),考虑到还会有Interface3Interface4,我如何编写代码来调用每个继承接口的foo()

共有3个答案

危钱明
2023-03-14

C 17中的折叠表达式有助于:

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

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

纪辰沛
2023-03-14

灵感来源于使用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);
    }
};

孙帅
2023-03-14

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

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

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

ObjectWithTemplate<Interface1, Interface1> object;

ObjectWithTemplate<Interface1, SomethingDerivedFromInterface1> object2;

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

 类似资料:
  • 问题内容: 在创建Java程序时,我遇到了一个问题, 子类构造函数通过调用超类的方法抛出错误 代码类似于以下内容: 错误是这样的: 为什么会这样? 问题答案: 超类没有默认的构造函数。因此,您需要将适当的构造函数参数传递给超类: (在和构造函数中,将其作为第一行。)在两种情况下,您都应删除该行。 通常,如果构造函数不是以or 语句开头(并且您只能使用其中之一,而不能同时使用两者),则默认情况下使用

  • 默认任何类都是基础继承自Any(与java中的Object类似),但是我们可以继承其它类。所有的类默认都是不可继承的(final),所以我们只能继承那些明确声明open或者abstract的类: open class Animal(name: String) class Person(name: String, surname: String) : Animal(name) 当我们只有单个构造器时

  • 关于下一个代码,我有一些问题: > 类专业化

  • 我想根据传递给类的模板参数实现一个实现开关: 如果传递的模板类型派生自特定类(此处:Serializable),则创建该类型实例的容器DataElement应派生自SerializableElement,并重载从其继承的两个纯虚拟方法(此处:unloadTo和loadFrom) 然而,如果传递的模板类型不是从Serializable派生的,那么DataElement不应该从Serializable

  • Jinja 最为强大的地方在于他的模板继承功能,模板继承允许你创建一个基础的骨架模板, 这个模板包含您网站的通用元素,并且定义子模板可以重载的 blocks 。 听起来虽然复杂,但是其实非常初级。理解概念的最好方法就是通过例子。 基础模板 在这个叫做 layout.html 的模板中定义了一个简单的 HTML 文档骨架,你可以 将这个骨架用作一个简单的双栏页面。而子模板负责填充空白的 block:

  • 模板继承可以减少页面内容的重复定义,实现页面内容的重用 典型应用:网站的头部、尾部是一样的,这些内容可以定义在父模板中,子模板不需要重复定义 block标签:在父模板中预留区域,在子模板中填充 extends继承:继承,写在模板文件的第一行 定义父模板base.html { % block block_name % } 这里可以定义默认值 如果不定义默认值,则表示空字符串 { %