如何重写 QObject::findChildren 以仅返回派生类型

How to override QObject::findChildren to return only the derived type

本文关键字:findChildren 返回 类型 派生 QObject 何重写 重写      更新时间:2023-10-16

通过回答我自己的另一个问题(这里),我发现QObject::findChildren<T>将返回任何通过reinterpret_cast<T>的孩子。

我想覆盖该行为,以便我只获得派生类型。

这是因为我有一个复合模式,其中所有项目都属于相同的基本类型,但我想使用 findChildren 来查找特定的子类。

我尝试覆盖查找儿童,如下所示:

template <class T> 
QList<T> Section::findChildren(QString name)
{
  QList<T> siblings = QObject::findChildren<T>(name);
  QList<T> children;
  for(int i=0; i < siblings.size(); i++)
  {    
    T test = siblings.at(i);
    T child = dynamic_cast<T>(test);
    if(child)
      children << child;
  }
  return children;
}

在我的示例中,我说四个项目是一个子项目,两个是一种类型,两个是另一种类型,具有相同的基类。我传递了 T 的派生类型之一,并且按预期(现在)QObject::findChildren 给出了所有四个孩子。但我预计dynamic_cast只会成功两次,它成功了四次。如果我将返回的四个项目列表传递到模板函数之外,我可以成功地将其剔除到我要查找的两个项目。

编辑:OP 发现他在类层次结构中错误地使用了Q_OBJECT宏。我将保留他接受的原始答案,但正确答案是必须在基类和派生类中使用Q_OBJECT宏。

原答案:如果QObject::findObject()真的使用reinterpret_cast<>,那么即使不能表示该类型,所有要T的强制转换也会成功。根据 API 描述,这是没有意义的。但是,假设您在这一点上是正确的,那么您的实现是有缺陷的,因为您获得的兄弟姐妹列表已经T指针,因为reinterpret_cast<>。相反,您应该使用 QObject然后使用 dynamic_cast<> 来清除您想要的实例,如下所示:

template <class T> 
QList<T> Section::findChildren(QString name)
{
  QList<QObject*> siblings = QObject::findChildren<QObject*>(name);
  QList<T> children;
  for(int i=0; i < siblings.size(); i++)
  {    
    QObject* test = siblings.at(i);
    T child = dynamic_cast<T>(test);
    if(child)
      children << child;
  }
  return children;
}