繁体   English   中英

有没有更简单的方法可以从QList转换 <Class*> 到QList <QPointer<Class> &gt;?

[英]Is there an easier way to convert from QList<Class*> to QList<QPointer<Class>>?

我有几个具有QList<ClassName *>类型的属性的QList<ClassName *> 我使用原始指针来表示所有权。 因为我们不想QList<QPointer<ClassName>>原始指针,所以此方法的访问器将返回QList<QPointer<ClassName>> 问题在于,目前每个访问器或多或少都如下所示:

QList<QPointer<ClassName>> values;
ClassName* value;
foreach(value, m_values){
    values.append(QPointer<ClassName>(value));
}
return values;

在某些情况下,我们使用的容器与QList不同,有时容器中的值是const。 现在,我想知道是否存在一种不需要我将其复制/粘贴到每个访问者的方法,因为感觉要么应该有更好的方法,要么首先是我们做错了。

我使用原始指针来表示所有权。

那就别这样 在C ++ 11中,根据需要使用std::unique_ptrstd::shared_ptr Qt本身使用QObject指针而不暗示所有权。 例如QObject::children()返回QObjectList = QList<QObject*> 我认为使用QPointer事情变得过于复杂。 为了最小化对其他代码的影响,只需返回QObjectList

如果对象列表是恒定的(但不一定是对象本身),则可以一次创建可访问容器:

class MyClass {
  std::list<QObject> m_gadgets;
  QList<QPointer<QObject>> m_userGadgets; // or std::list<...>
public:
  typedef const std::list<QObject> Gadgets;
  MyClass() {
    m_gadgets.emplace_back(...);
    ...
    m_userGadgets.reserve(m_gadgets.size());
    for (auto & gadget : m_gadgets)
      m_userGadgets.push_back(QPointer(&gadget));
  }
  Gadgets & gadgets() const { return m_userGadgets; }
};

如您所见,您不需要使用原始指针来存储QObject 您可以使用例如std::list和emplacement或std::array 这暴露了API的脆弱性:它对内部使用的容器非常敏感。

通过迭代器访问容器通常是惯用的。 您可以通过迭代器公开对象容器,用户应该编写只需要特定黑盒迭代器类型的代码。

例如:

class MyClass {
  std::list<QObject> m_gadgets;
public:
  typedef std::list<QObject>::const_iterator GadgetsConstIterator;
  GadgetsConstIterator gadgetsBegin() const { return m_gadgets.begin(); }
  GadgetsConstIterator gadgetsEnd() const { return m_gadgets.end(); }
};

void gadgetsUser(MyClass::GadgetsConstIterator begin, MyClass::GadgetsConstIterator end);

不管GadgetsConstIterator的具体类型是GadgetsConstIterator ,只要它属于相同的迭代器类别并且用户对迭代器没有其他不必要的假设,这将起作用。

您还可以将对象容器公开为通用容器,应指示用户使用std::begin(container)std::end(container)访问该容器。 这样,您甚至可以使用原始C数组(颤抖):

class MyClass {
  QObject m_gadgets[5];
  // or
  std::array<QObject, 5> m_gadgets;
  // or
  std::list<QObject> m_gadgets;
public:
  // adjust as necessary
  typedef QObject Gadgets[5];
  typedef const QObject ConstGadgets[5];
  ConstGadgets & gadgets() const { return reinterpret_cast<ConstGadgets&>(m_gadgets); }
  Gadgets & gadgets() { return m_gadgets; }
}

void gadgetsUser1(MyClass::ConstGadgets & gadgets) {
  for (auto gadget : gadgets)
    qDebug() << gadget.metaObject()->className();
}

void gadgetsUser2(MyClass::ConstGadgets & gadgets) {
  for (auto it = std::begin(gadgets); it != std::end(gadgets); it++)
    qDebug() << gadget.metaObject()->className();
}

最后,您还可以完全隐藏集合类型,只暴露经过容器的烘焙forEach

class MyClass {
  std::list<QObject> m_gadgets;
public:
  template <typename F> forEachGadget(F && fun) const { 
    for (auto const & gadget : m_gadget) fun(gadget);
  }
  template <typename F> forEachGadget(F && fun) { 
    for (auto & gadget : m_gadget) fun(gadget);
  }
};

void OtherClass::gadgetUser(MyClass & c) {
  c.forEachGadget([this](const QObject & gadget) { qDebug() << &gadget; }
}

这里有许多可能的变化,请根据感觉最自然的情况进行选择。 但是,在所有情况下,用户代码都不得依赖于为访问对象而接收的具体容器或迭代器类型。

最后,您不应忘记QObject是一个QObject容器。 您可以通过简单地将对象存储为容器对象的子代来提供更大的灵活性。 这样,您可以使用相同的容器类型返回对象列表和树:

class MyClass {
  QObject m_gadgets;
public:
  MyClass() {
    new QObject(&m_gadgets); // list element 1
    new QObject(&m_gadgets); // list element 2
  }
  const QObject & gadgets() const { return m_gadgets; }
}

void gadgetsUser(const QObject & gadgets) {
  for (auto gadget : gadgets.children()) { qDebug() << gadget; }
  // or, DFS of a tree
  for (auto gadget : gadgets.children()) {
    qDebug() << gadget;
    gadgetsUser(*gadget);
  }
  // or, BFS of a tree
  for (auto gadget : gadgets.children())
    qDebug() << gadget;
  for (auto gadget : gadgets.children())
    gadgetsUser(*gadget);
}

请注意, QObject将其子级保留为具有稳定顺序的内部列表。 QObject::children()仅返回对内部持有的子代列表的引用,因此它的O(1)开销很小。 向对象添加子对象会将对象添加到其内部子对象列表中-尽管没有记录,但至少从Qt 4.0开始就是这种情况。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM