首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是否有一种从QList<Class*>到QList<QPointer<Class>>的更简单的转换方式?

是否有一种从QList<Class*>到QList<QPointer<Class>>的更简单的转换方式?
EN

Stack Overflow用户
提问于 2016-04-01 13:30:53
回答 1查看 1K关注 0票数 0

我有几个具有QList<ClassName *>类型属性的类。我使用原始指针来表示所有权。访问器将返回QList<QPointer<ClassName>>,因为我们不想发送原始指针。问题是,目前每个访问器大致如下所示:

代码语言:javascript
复制
QList<QPointer<ClassName>> values;
ClassName* value;
foreach(value, m_values){
    values.append(QPointer<ClassName>(value));
}
return values;

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-04-01 14:38:26

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

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

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

代码语言:javascript
复制
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的脆弱性:它对内部使用的容器非常敏感。

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

例如:

代码语言:javascript
复制
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的具体类型是什么,只要它属于相同的迭代器类别,并且用户没有对迭代器做出其他不合理的假设,这都是可行的。

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

代码语言:javascript
复制
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

代码语言:javascript
复制
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容器。您可以通过简单地将对象存储为容器对象的子对象来提供更大的灵活性。这样,您可以使用相同的容器类型返回对象列表和树:

代码语言:javascript
复制
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)成本非常小。将子对象添加到对象后,会将对象追加到其子对象的内部列表中--尽管没有文档化,但至少从Qt4.0开始就是如此。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36357677

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档