代码之家  ›  专栏  ›  技术社区  ›  TSG

创建多个对象类型的QList

  •  2
  • TSG  · 技术社区  · 12 年前

    我需要创建各种类类型(classA、classB、classC)的多个实例,然后将它们存储在一个列表中。是否可以动态创建这些对象,然后将它们添加到单个QList中?类似于:

    QList<QObject> mylist;
    mylist.append(classA());
    mylist.append(classB());
    mylist.append(classC());
    

    这不会编译,因为对象不是QObject类型。我可以将它们静态转换为QObject,但我是否能够typeid.name()来确定它们的原始类型?(以后再把它们扔回去)?

    我找到了一个例子 here 使用QList<QVariant>,但编译器抱怨:

    错误:没有用于调用“QVariant::QVariant(classA&)”的匹配函数

    对于此代码:

    QList<QVariant> mylist;
    mylist.append(QVariant(tempObj));
    

    更新:

    我通过在追加操作期间创建对象并使用::fromValue来编译它。

    mylist.append(QVariant::fromValue(ClassA(1,2,3)));
    

    不确定这是否正确。1-这是否会导致内存泄漏/在append语句中创建对象时出现问题?2-为什么我需要::fromValue来实现这一点?(这是否只是对象的第二个副本?)

    我在构造函数中放置了一个qDebug,我看到带参数的构造函数被调用了两次,然后复制构造函数被调用一次,而默认(无参数)构造函数从未被调用。我不明白。。。

    2 回复  |  直到 12 年前
        1
  •  4
  •   user2836797 user2836797    12 年前

    您可以使用 QVariant 其可以容纳任意数量的不同类型: QVariant API

    使用 Q变量 对于自定义类型,您需要在元类型系统中注册它: QMetaType 这意味着使用 Q_DECLARE_METATYPE(MyClass) Q_DECLARE_METATYPE()

    QVariant是为保存不同类型的对象而设计的,当程序员想要通过Qt的接口传递用户定义的类型,而Qt本身无法知道程序员想要使用哪种类型时,QVariant被用于各种Qt约定中。

    要转换回原始类型,请使用以下组合 QVariant::canConvert() 和 QVariant::value() :

    QVariant v;
    
    MyCustomStruct c;
    if (v.canConvert<MyCustomStruct>())
        c = v.value<MyCustomStruct>();
    
    v = 7;
    int i = v.value<int>();                        // same as v.toInt()
    QString s = v.value<QString>();                // same as v.toString(), s is now "7"
    MyCustomStruct c2 = v.value<MyCustomStruct>(); // conversion failed, c2 is empty
    

    自定义类型必须提供:

    1. 公共默认构造函数,
    2. 公共复制构造函数,以及
    3. 公共析构函数。

    以下内容 Message 类是可接受的自定义类型的示例,用于 Q变量

    class Message
    {
     public:
       Message();
       Message(const Message &other);
       ~Message();
    
       Message(const QString &body, const QStringList &headers);
    
       QString body() const;
       QStringList headers() const;
    
     private:
       QString m_body;
       QStringList m_headers;
    };
    

    您还可以声明自己的“元类型包装器”,该包装器保存类型和类型描述。最简单的例子:

    template <typename T>
    class AnyType
    {
    public:
      enum THE_TYPE { MT_INT, MT_STRING };
    
      AnyType(T value, THE_TYPE type) : value(value), type(type) { }
      THE_TYPE getType() { return type; }
      T getValue() { return value; }
    
    private:
      T value;
      THE_TYPE type;
    }
    
        2
  •  2
  •   HostileFork says dont trust SE    12 年前

    我可以将它们静态转换为QObject

    不,你不能!这是非法的:

    QList<QObject> mylist;
    

    QObjects有身份的概念,并且是不可复制的类型。您必须通过指针操作它们,这将是QObject值的列表。

    但更一般地说(关于寻求通过选角避开这类事情)。。。QList和其他模板化容器专门为其参数化的对象类型分配一定数量的内存。因此 QList<A> 在实现级别,每个项目只有足够的存储空间 sizeof(A) ,而a QList<B> 只能保存以下项目 sizeof(B) .

    所以首先:如果你投了一个 对象 与铸造 指针,指针 那么你真的失去了你无法找回的信息。。。如果你甚至可以让编译器让你这样做。第二:即使你有一个槽,可以将指针转换为“punned类型”,然后由于这样做带来的各种陷阱而再次返回,你也需要小心。尽管指向不同类型的指针与指针大小相同,但你必须考虑 Strict Aliasing Requirement .

    你可以用类似 QVariant 正如@snownandotherjoys所建议的那样。如果你想更“标准”,你可以看看 boost::variant .

    但人们常说,需要像这样的运行时输入的情况可能意味着需要重新审视设计。如果类a、类B和类C如此不同,以至于它们没有共同的接口,那么将它们放在一个引人注目的集合中是什么原因呢?你能用一堆毫无共同点的东西做些什么?虽然这些情况 做 提出(并激发变体的存在),退后一步,问问你是否真的有这种情况是很有价值的。