Kwin代码阅读——模板类

首先,理解一些基本概念:

1. 模板:
   在C++中,模板允许我们编写通用的代码,可以接受不同的数据类型,而不需要重复编写代码。模板有两种主要形式:函数模板和类模板。这里我们讨论的是类模板。

2. 继承:
   继承是面向对象编程中的一个特性,允许一个类(子类)继承另一个类(父类)的属性和方法。子类可以扩展或重写父类的方法。

代码分解

我们来看一下代码:

template<typename Loader, typename QueueType>
class EffectLoadQueue : public AbstractEffectLoadQueue {
    // 类的内容
};

模板声明

template<typename Loader, typename QueueType>

        这一行是模板声明,它告诉编译器我们将定义一个类模板,其中包含两个类型参数(`Loader`和`QueueType`)。这些类型参数是占位符,表示在使用这个模板时可以传入任意类型。

类定义

class EffectLoadQueue

        这一行开始定义模板类`EffectLoadQueue`。

继承

: public AbstractEffectLoadQueue

        这一行表示模板类`EffectLoadQueue`继承自一个基类`AbstractEffectLoadQueue`。这意味着`EffectLoadQueue`类可以使用`AbstractEffectLoadQueue`类中的所有公共和保护成员。

整个模板类的作用

        模板类`EffectLoadQueue`的作用是创建一个通用的加载队列。通过使用模板参数`Loader`和`QueueType`,可以在创建具体实例时指定不同的加载器和队列项类型。

具体例子

        为了帮助理解,让我们考虑一个具体的例子:

        假设我们有一个加载器类`MyLoader`和一个队列项类型`int`,我们希望使用`EffectLoadQueue`类来处理加载队列。
 

class MyLoader {
public:
    void loadEffect(int item, int flags) {
        // 实际的加载代码
    }
};

using LoadEffectFlags = int; // 假设LoadEffectFlags是一个整数标志

int main() {
    MyLoader loader;
    EffectLoadQueue<MyLoader, int> queue(&loader);
    queue.enqueue({42, 0}); // 添加一个队列项
    queue.dequeue(); // 手动调用以处理队列项
    return 0;
}

        在这个例子中:

        1. MyLoader:
           定义了一个具体的加载器类`MyLoader`,它有一个`loadEffect`方法,该方法接受一个`int`类型的项和一个`int`类型的标志。

        2. EffectLoadQueue<MyLoader, int> queue:
           创建了一个`EffectLoadQueue`类的实例,传入了具体的类型参数`MyLoader`和`int`。这意味着这个队列处理`int`类型的队列项,并使用`MyLoader`进行加载。

代码片段的详细解释

        现在我们回到原始代码片段,逐行解释其作用。

template<typename Loader, typename QueueType>
class EffectLoadQueue : public AbstractEffectLoadQueue {
public:
    explicit EffectLoadQueue(Loader *parent)
        : AbstractEffectLoadQueue(parent),
          m_effectLoader(parent),
          m_dequeueScheduled(false) {}

    void enqueue(const QPair<QueueType, LoadEffectFlags> value) {
        m_queue.enqueue(value);
        scheduleDequeue();
    }

    void clear() {
        m_queue.clear();
        m_dequeueScheduled = false;
    }

protected:
    void dequeue() override {
        if (m_queue.isEmpty()) {
            return;
        }
        m_dequeueScheduled = false;
        const auto pair = m_queue.dequeue();
        m_effectLoader->loadEffect(pair.first, pair.second);
        scheduleDequeue();
    }

private:
    void scheduleDequeue() {
        if (m_queue.isEmpty() || m_dequeueScheduled) {
            return;
        }
        m_dequeueScheduled = true;
        QMetaObject::invokeMethod(this, &AbstractEffectLoadQueue::dequeue, Qt::QueuedConnection);
    }

    Loader *m_effectLoader;
    bool m_dequeueScheduled;
    QQueue<QPair<QueueType, LoadEffectFlags>> m_queue;
};
- 构造函数:
  explicit EffectLoadQueue(Loader *parent)
      : AbstractEffectLoadQueue(parent),
        m_effectLoader(parent),
        m_dequeueScheduled(false) {}
  初始化基类`AbstractEffectLoadQueue`,同时初始化成员变量`m_effectLoader`和`m_dequeueScheduled`。

- enqueue方法:
  void enqueue(const QPair<QueueType, LoadEffectFlags> value) {
      m_queue.enqueue(value);
      scheduleDequeue();
  }
  将队列项添加到队列中,并调度一个`dequeue`操作。

- clear方法:
  void clear() {
      m_queue.clear();
      m_dequeueScheduled = false;
  }
  清空队列并重置调度标志。

- dequeue方法:
  void dequeue() override {
      if (m_queue.isEmpty()) {
          return;
      }
      m_dequeueScheduled = false;
      const auto pair = m_queue.dequeue();
      m_effectLoader->loadEffect(pair.first, pair.second);
      scheduleDequeue();
  }
  从队列中取出一个项,并使用加载器加载该项,然后再次调度`dequeue`操作(如果队列不为空)。

- scheduleDequeue方法:
  void scheduleDequeue() {
      if (m_queue.isEmpty() || m_dequeueScheduled) {
          return;
      }
      m_dequeueScheduled = true;
      QMetaObject::invokeMethod(this, &AbstractEffectLoadQueue::dequeue, Qt::QueuedConnection);
  }
  如果队列不为空且没有调度过`dequeue`操作,则调度一个`dequeue`操作。

        这段代码定义了一个模板类`EffectLoadQueue`,用于创建一个通用的加载队列。通过使用模板参数,可以在创建实例时指定不同的加载器和队列项类型。这使得代码更加通用和可复用。继承关系允许`EffectLoadQueue`利用基类的接口和多态性特性,同时提供具体的实现。

——————————————————————————————————————————

        可能看上面的描述还是会觉得哪里不清楚,下面是更详细的介绍,这个模板参数的作用。

二、模板参数的作用

        模板参数`Loader`和`QueueType`在`EffectLoadQueue`类中被多处使用,用于指定不同的加载器类型和队列项类型。通过这些模板参数,`EffectLoadQueue`类能够处理不同类型的加载器和队列项,而不需要重复编写代码。

具体化模板参数

假设我们有以下两个具体类型:

- 一个名为`MyLoader`的加载器类
- 一个`int`类型的队列项

我们可以用这些具体类型实例化`EffectLoadQueue`模板类:

class MyLoader {
public:
    void loadEffect(int item, int flags) {
        // 实际的加载代码
    }
};

using LoadEffectFlags = int; // 假设LoadEffectFlags是一个整数标志

int main() {
    MyLoader loader;
    EffectLoadQueue<MyLoader, int> queue(&loader);
    queue.enqueue({42, 0}); // 添加一个队列项
    queue.dequeue(); // 手动调用以处理队列项
    return 0;
}

模板参数的具体用途

1. 构造函数:

  explicit EffectLoadQueue(Loader *parent)
       : AbstractEffectLoadQueue(parent),
         m_effectLoader(parent),
         m_dequeueScheduled(false) {}

         在这里,`Loader`被具体化为`MyLoader`,所以`parent`是一个指向`MyLoader`对象的指针。

2. enqueue方法:

   void enqueue(const QPair<QueueType, LoadEffectFlags> value) {
       m_queue.enqueue(value);
       scheduleDequeue();
   }

        在这里,`QueueType`被具体化为`int`,所以`value`是一个`QPair<int, LoadEffectFlags>`类型。

3. dequeue方法:

   void dequeue() override {
       if (m_queue.isEmpty()) {
           return;
       }
       m_dequeueScheduled = false;
       const auto pair = m_queue.dequeue();
       m_effectLoader->loadEffect(pair.first, pair.second);
       scheduleDequeue();
   }

        在这里,`pair`的类型是`QPair<int, LoadEffectFlags>`,所以`pair.first`是一个`int`,`pair.second`是一个`LoadEffectFlags`(即`int`)。

4. 成员变量:

   Loader *m_effectLoader;
   QQueue<QPair<QueueType, LoadEffectFlags>> m_queue;

        这里,`Loader`被具体化为`MyLoader`,所以`m_effectLoader`是一个指向`MyLoader`的指针;`QueueType`被具体化为`int`,所以`m_queue`是一个`QQueue<QPair<int, LoadEffectFlags>>`。

模板的好处

        通过使用模板,我们可以创建一个通用的类,而不是为每种加载器和队列项类型编写特定的类。这大大提高了代码的重用性和灵活性。

        如果我们有另一种加载器和不同类型的队列项,例如:

class AnotherLoader {
public:
    void loadEffect(std::string item, int flags) {
        // 实际的加载代码
    }
};

int main() {
    AnotherLoader loader;
    EffectLoadQueue<AnotherLoader, std::string> queue(&loader);
    queue.enqueue({"example", 1});
    queue.dequeue();
    return 0;
}

        我们只需传入不同的模板参数,就可以使用相同的`EffectLoadQueue`模板类处理不同类型的加载器和队列项,而不需要修改`EffectLoadQueue`类的代码。这是模板的强大之处。

        在使用模板类时,模板参数是在你创建模板类的实例时指定的,而不是在构造函数中传递的。模板参数允许你在类的定义中使用这些参数来指定类型,而不需要在构造函数中传递这些类型信息。

1. 模板参数在实例化时指定:模板参数是在你创建模板类的实例时指定的,而不是在构造函数中传入的。
   
2. 构造函数参数是具体类型:构造函数中的参数是具体类型(如指向`Loader`类型的指针),而不是模板参数本身。
   
3. 模板参数在类中使用:一旦模板参数在类实例化时被指定,你可以在整个类中使用这些参数来定义成员变量和方法。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值