2

我最近拿起了一个我前段时间正在开发的应用程序。

不久之后,我偶然发现了继承问题。

我有一个名为 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 中前向声明平台并在 platform.h 中包含 games.h 解决了这个问题

既然这已经解决了,我编译了我的程序并得到了以下我真的不明白的抱怨。

xxxxx\mingw47_32\include\QtCore\qmetatype.h:382: error: cannot allocate an object of abstract type 'ModelBase'

好吧,很公平..但我从来没有真正直接在类中定义 ModelBase。只能从它派生。

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

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

我真的不知道这里发生了什么。

我尝试在games.h中根本不使用指针,但后来我得到了我也不理解的不同类型的编译器错误;

xxxx\game.h:38: error: field 'm_platform' has incomplete type

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

我假设我不知道这种继承应该如何在这里工作。

我将 ModelBase 定义为元类型的原因是因为我希望 ModelBase 及其子项在 QVariant 中/从 QVariant 中包装/解包

4

4 回答 4

8

最后一个错误发生是因为您的类中不能有不完整类型的对象。编译器将不知道要为该对象分配多少空间,因此您的类的内存布局将不知何故未定义。相反,“指向不完整的指针”是可能的。

我不喜欢 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 类参考说:

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

正如我所提到的:无法构造抽象类。

请参阅[Qt-interest] Q_DECLARE_METATYPE 和抽象类

2011 年 8 月 8 日星期一 12:36:16 Schimkowitsch Robert 写道:

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

你没有。元类型需要默认可构造、可公开破坏、可复制和可分配。

根本无法构造抽象类型。根据抽象的定义,您也不想复制它们,因为这样做会剪切您拥有的专用对象。

您很可能希望将指针的元类型注册 到抽象类。

于 2013-04-22T09:30:14.913 回答
5

on 抽象类Q_DECLARE_METATYPE确实是个问题。这并没有“将类定义为元类型”,它使 Qt 的 MOC 可以使用该类,用于在信号/插槽参数中传递它、使其可用QVariant等目的。但是,您不能在抽象类上执行此操作 - 这没有道理。你确定你的意思不是:

Q_DECLARE_METATYPE(ModelBase*)

关于其余的警告——当编译器注意到一个错误时,他们中的大多数会尝试在你的源代码中找到其他问题。有时它运行良好,有时它只是给你虚假的警告。修复Q_DECLARE_METATYPE错误,然后处理其余部分。

于 2013-04-22T09:35:08.833 回答
1

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

因此,将它用于虚拟类的对象是没有意义的,因为您可以从一开始就构造一个虚拟类的对象。首先是Q_DECLARE_METATYPE(ModelBase*)行不通的,因为参数需要是一个类型(解析真的很基础)。其次,这不是必需的,因为您可以在 Qt 中使用任何指针,而无需向系统声明它。

于 2013-04-22T09:43:36.150 回答
0

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

通过 UsingQVariant::canConvert<ModelBase*>可以在以后确定指针的类型,因此声明类型化指针而不是使用 default 可能很有用void*

于 2017-10-10T15:28:08.750 回答