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 として宣言されているという事実は、残りのコードを読む上で心に留めておくべきことです。

この基本クラスからいくつかのクラスを派生させました。この例では、ほとんどの問題を引き起こす 2 つを使用します。

#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

これでコードが配置されました...

最初の問題は、循環依存関係にあります。

プラットフォームには多くのゲームがあり、ゲームには 1 つのプラットフォームがあります。

games.h でプラットフォームを宣言し、platforms.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 宣言と forward 宣言の両方を使用してみましたが、いずれも問題を共有しています。また、games.h ファイルで前方クラス宣言をインクルード (循環依存の問題を引き起こす platform.h を除く) に置き換えると、不完全な型のすべての問題が消えることに注意してください (私が知る限り、m_platform を除く)。 、私はそれを前方宣言するしかありません)

この継承がここでどのように機能するかについての知識が不足していると思います。

ModelBase をメタタイプとして定義した理由は、ModelBase とその子を 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 Class Referenceには次のように書かれています:

Q_DECLARE_METATYPE ( Type )このマクロは、パブリック デフォルト コンストラクター、パブリック コピー コンストラクター、およびパブリック デストラクタを提供する限り、型 Type を QMetaType に認識させます。タイプ Type を QVariant のカスタム タイプとして使用する必要があります。

私が述べたように、抽象クラスは構築できません。

[Qt-interest] Q_DECLARE_METATYPE と抽象クラスを参照してください:

2011 年 8 月 8 日月曜日 12:36:16 Schimkowitsch Robert は次のように書いています。

抽象基本クラスのメタタイプを宣言するにはどうすればよいですか? Q_DECLARE_METATYPE-docs でそれを禁止するものは何も見たことがありません。

あなたはそうしない。メタタイプは、デフォルトで構築可能、公的に破壊可能、コピー可能、および割り当て可能である必要があります。

抽象型はまったく構築できません。抽象の定義によっても、それらをコピーしたくありません。それを行うと、あなたが持っていた特殊なオブジェクトが剪断されるからです。

おそらく、ポインタのメタタイプを 抽象クラスに登録したいと思うでしょう。

于 2013-04-22T09:30:14.913 に答える
5

Q_DECLARE_METATYPEon 抽象クラスは確かに問題です。これは「クラスをメタタイプとして定義する」のではなく、そのクラスを 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内に格納されたポインターのタイプを見つけたいコードを書いているときに、同様の問題に遭遇しました。

を使用QVariant::canConvert<ModelBase*>することで、後でポインターの型を判別できるため、デフォルトを使用する代わりに、型付きポインターを宣言すると便利な場合がありますvoid*

于 2017-10-10T15:28:08.750 に答える