Qt继承和实例化问题

Qt inheritance and instantiation problems

本文关键字:问题 实例化 继承 Qt      更新时间:2023-10-16

我最近捡起了一个我之前做过的应用程序。

不久之后,我就遇到了继承的问题。

我有一个叫做ModelBase的基类,它有一个纯虚方法,使它成为一个抽象类。类如下所示:

#ifndef MODELBASE_H
#define MODELBASE_H
#include <QMetaType>
#include <QString>
class ModelBase
{
public:
    ModelBase();
    virtual ~ModelBase();
    long getId() const;
    void setId(const long id);
    virtual QString toString() const = 0;
private:
    long m_id;
};
Q_DECLARE_METATYPE(ModelBase)
#endif // MODELBASE_H

声明为METATYPE的事实可能是阅读其余代码时需要记住的。

我从这个基类派生了几个类。对于这个例子,我将使用给我带来最多问题的两个。

#ifndef PLATFORM_H
#define PLATFORM_H
#include <QDate>
#include "modelbase.h"
#include "game.h"
class Platform : ModelBase
{
public:
    Platform();
    ~Platform();
    QString toString() const;
    QString getName();
    QDate getPublishDate();
    void setName(QString name);
    void setPublishDate(QDate publishDate);
private:
    QString m_name;
    QDate m_publishDate;
    QList<Game*> m_games;
};
#endif // PLATFORM_H

可以看到,头文件还包括来自父类ModelBase的虚方法。

最后但并非最不重要;问题类:

#ifndef GAME_H
#define GAME_H
#include <QDate>
#include "modelbase.h"
class Platform;
class Publisher;
class Genre;
class Game : ModelBase
{
public:
    Game();
    ~Game();
    QString getTitle();
    Publisher* getPublisher();
    Genre* getGenre();
    Platform* getPlatform();
    QDate getPublishDate();
    QString getLentTo();
    void setTitle(QString title);
    void setPublisher(Publisher &publisher);
    void setGenre(Genre &genre);
    void setPlatform(Platform &platform);
    void setPublishDate(QDate date);
    void setLentTo(QString lentTo);
    QString toString() const;
private:
    QString m_title;
    Publisher *m_publisher;
    Genre *m_genre;
    Platform *m_platform;
    QDate m_publishDate;
    QString m_lentTo;
};
#endif // GAME_H

现在代码已经就绪…

第一个问题是循环依赖。

一个平台有许多游戏,一个游戏有一个平台。

我通过在games.h中向前声明平台并在platforms.h中包含games.h来解决这个问题

现在解决了这个问题,我编译了我的程序,得到了以下抱怨,我真的不理解。

xxxxxmingw47_32includeQtCoreqmetatype.h:382: error: cannot allocate an object of abstract type 'ModelBase'

好吧…但是我从来没有真正直接在类中定义ModelBase。只从它推导。

我在同一日志中得到的另一个错误是:

xxxxmingw47_32includeQtCoreqmetatype.h:-1: In instantiation of 'static void* QtMetaTypePrivate::QMetaTypeFunctionHelper<T, Accepted>::Create(const void*) [with T = ModelBase; bool Accepted = true]':

我真的不知道这是怎么回事。

我试着不使用指针在所有的游戏。h,但后来我得到不同类型的编译器错误,我不理解;

xxxxgame.h:38: error: field 'm_platform' has incomplete type

我试过使用#include和forward声明,但它们都有共同的问题。还请注意,如果在games.h文件中,我用include替换了向前的类声明(除了platform.h,这将带回循环依赖问题),则所有不完整类型的问题都消失了(除了m_platform,因为据我所知,我别无选择,只能向前声明它)

我想我对这里的继承应该如何工作缺乏了解。

我将ModelBase定义为元类型的原因是我希望ModelBase及其子类在QVariant

中包装/取消包装,最后一个错误发生是因为您不能在类中拥有不完整类型的对象。编译器将不知道要为这个对象分配多少空间,因此类的内存布局将以某种方式未定义。相反,可以使用"指向不完整的指针"。

我不是进入Qt,但它看起来像你的Q_DECLARE_METATYPE()结果在一个构造函数调用。根据定义,抽象类是不可构造的。

QMetaTypeFunctionHelper::Create:

static void *Create(const void *t)
{
  if (t)
    return new T(*static_cast<const T*>(t));
  return new T();
}

文档QMetaType Class Reference说:

Q_DECLARE_METATYPE (Type)只要提供一个公共默认构造函数、一个公共复制构造函数和一个公共析构函数,这个宏就使类型Type为QMetaType所知。需要在QVariant中使用type类型作为自定义类型。

如前所述:抽象类不能被构造。

参见[Qt-interest] Q_DECLARE_METATYPE和抽象类:

On Monday, 8 de August de 2011 12:36:16 Schimkowitsch Robert写道:

如何声明抽象基类的元类型?我见过Q_DECLARE_METATYPE-docs中没有任何禁止它的内容。

你不。元类型需要是默认可公开构造的可销毁、可复制、可赋值。

抽象类型根本不能被构造。根据抽象的定义同样,你也不想复制它们,因为那样做会剪切你有专门的对象。

您很可能想要注册指针的元类型到抽象类

抽象类上的Q_DECLARE_METATYPE确实是一个问题。这不是"定义一个类的元类型",它使该类可用于Qt的MOC的目的,如传递它周围的信号/槽参数,使其在QVariant等可用。但是,您不能在抽象类上这样做——这没有意义。你确定你不是这个意思吗?

Q_DECLARE_METATYPE(ModelBase*)

关于其余的警告——当编译器注意到一个错误时,它们中的大多数都试图在您的源代码中查找其他问题。有时它很有效,有时它只是给你虚假的警告。修复Q_DECLARE_METATYPE错误,然后工作在其余的

Q_DECLARE_METATYPE是当你想在QVariant (Qt高级联合)中使用特定类的对象或在信号和插槽连接中使用这些对象时使用的。

因此,将它用于虚类的对象是没有意义的,因为您可以首先构造虚类的对象。首先,Q_DECLARE_METATYPE(ModelBase*)不能工作,因为参数需要是类型(解析非常基本)。其次,它不是必需的,因为您可以在Qt中使用任何指针而无需向系统声明它。

我刚刚遇到了一个类似的问题,在编写一些代码时,我后来想找到QVariant中存储的指针的类型。

通过使用QVariant::canConvert<ModelBase*>,可以在稍后确定指针的类型,因此声明一个类型化指针而不是使用默认的void*可能会很有用。