2013-04-22 3 views
1

저는 최근 얼마 전 일하고 있던 응용 프로그램을 선택했습니다.Qt 상속 및 인스턴스화 문제

나는 상속에 관한 문제를 이미 우연히 발견 한 직후입니다.

나는 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 

그것이 메타 타입으로 선언되어 있다는 사실은 아마 코드의 나머지 부분을 읽기 위해 명심해야 할 일이다.

이 기본 클래스에서 여러 클래스를 파생 시켰습니다. 이 예제에서는 가장 문제가되는 두 가지를 사용하겠습니다.

#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 포함하여, 내 프로그램을 컴파일하고 다음과 같은 불만을 얻을 해결하는 내가 정말 돈 이해하지 못해.

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 파일에서 include (전제 종속성 문제를 가져 오는 platform.h 제외)와 함께 포워드 클래스 선언을 바꾼다면 모든 문제는 불완전한 형태의 dissapear를 가지고 있습니다 (m_platform 제외). 왜냐하면 내가 아는 한, , 나는 선택의 여지가 있지만 앞으로 선언해야한다)

나는이 상속이 어떻게 작동해야하는지에 대한 지식이 없다고 가정한다.

내가 메타 타입으로 ModelBase를 정의하는 이유는 내가 QVariant

+0

흥미 롭습니다. 그리고 [그들의 ​​문서] (http://qt-project.org/doc/qt-4.8/custom-types.html)는 클래스가 추상적 일 수 있는지 여부를 말하지 않습니다. –

+0

atleast에 대해 아무 것도 찾을 수 없었습니다. : P –

+0

당신은 사적 상속을 사용하고 있다는 사실을 알고 있습니까? 대신 공용 상속을 사용해보십시오. –

답변

7

마지막 오류에서// 미개봉 포장 할 ModelBase와 아이를 원하기 때문에 당신이 당신의 클래스에서 불완전한 형식의 개체를 할 수 없기 때문에 발생하는 것입니다 .컴파일러는이 객체에 할당 할 공간의 크기를 알지 못하므로 클래스의 메모리 레이아웃이 어떻게 든 정의되지 않습니다. 대조적으로 "불완전한 포인터"가 가능합니다.

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 (유형)이 매크로는 기본 public 생성자를 제공하는만큼 QMetaType 알려진 유형 유형을하게하는 공공 복사 생성자 및 공용 소멸자. QVariant에서 유형 유형을 사용자 정의 유형으로 사용해야합니다.

앞서 언급했듯이 : 추상 클래스는 구성 할 수 없습니다. 2011 12시 36분 16초 Schimkowitsch 로버트 쓴 드 8월 드 월요일 8 일

:

가 어떻게 추상 기본 클래스의 메타 타입을 선언 할

[Qt-interest] Q_DECLARE_METATYPE and abstract classes를 참조하십시오? 나는 그것을 금지 할 Q_DECLARE_METATYPE-docs에 을 보지 못했습니다.

그렇지 않습니다. 메타 타입은 기본적으로 구성 가능해야하며 공개적으로 파괴 가능하고 복사 가능하며 할당 가능해야합니다.

추상 유형을 구성 할 수 없습니다. 추상적 인 정의 의 정의에 따라, 당신이 가지고있는 특수 객체를 전단하는 것처럼 복사하지 않을 것입니다. 가능성 이보다

더, 당신은 추상 클래스에 포인터 의 메타 타입을 등록 할 수 있습니다.

+0

이것은 훌륭한 대답이며 Daniel도 내가했던 것보다 빠릅니다. –

+0

대니얼 베버는 답변 해 주셔서 감사합니다. 대부분의 컴파일 오류를 없애고 새로운 통찰력을 얻었습니다. 고마워. –

5

추상 클래스의 Q_DECLARE_METATYPE은 실제로 문제입니다. 이것은 "클래스를 메타 타입으로 정의"하지 않고 Qt의 MOC에서 signal/slot 매개 변수를 전달하는 것과 같은 목적으로 해당 클래스를 사용할 수있게하여 QVariant 등에서 사용할 수있게합니다. 그러나 클래스에서는이를 수행 할 수 없습니다. 추상적 - 그것은 말이되지 않습니다. - 컴파일러가 에러를 통지 할 때, 그들 중 대부분은 소스에 향후 다른 문제를 찾으려고

Q_DECLARE_METATYPE(ModelBase*) 

경고의 나머지 부분에 관하여 : 당신은 당신이 말은하지 않았다 확신합니다. 때때로 그것은 잘 작동하고 때로는 단지 당신에게 허위의 경고를줍니다. Q_DECLARE_METATYPE 오류를 수정 한 다음 나머지 작업을 수행하십시오.

+0

시간을내어 답변 해 주셔서 감사합니다. 나는 아직도 나에게 불분명 한 한 가지 문제가있다. ModelBase를 METATYPe로 만들면 모든 자식도 자동으로 METATYPE이 될 것이라고 생각했습니다. 그래서 ModelBase에 왜 그것을 썼습니다. 나는 이것이 주로 내 편이라는 지식 부족 때문이라고 생각하니? –

1

Q_DECLARE_METATYPE은 QVariant (Qt 고급 조합)에서 특정 클래스의 개체를 사용하거나 신호 및 슬롯 연결에서 이러한 개체를 사용하려는 경우에 사용됩니다.

그래서 가상 클래스의 객체를 구성 할 수 있기 때문에 가상 클래스의 객체에 사용하는 것은 의미가 없습니다. 우선 Q_DECLARE_METATYPE(ModelBase*)은 매개 변수가 형식이어야하기 때문에 작동하지 않습니다 (구문 분석은 실제로 기본입니다). 둘째, Qt에서 포인터를 시스템에 선언하지 않고 사용할 수 있기 때문에 필요하지 않습니다.

+0

설명해 주셔서 감사합니다. Q_DECLARE_METATYPE (ModelBase *)가 컴파일러 오류를 일으키는 것을 알았지 만, 런타임시 자신을 어떻게 처리하는지 알기 위해 시간이 좀 걸립니다. –

+0

컴파일러 오류 만이 아닙니다. 그것은 당신이 성취하고자하는 것에 관한 것입니다. 'Q_DECLARE_METATYPE (ModelBase *)'는 쓸모없는 *** 문장입니다. – UmNyobe

+0

내가 뭘 하려는지 ModelBase에서 상속하여 각 자식 클래스를 자동으로 METATYPE 수하는 것이 었습니다. 이것이 잘못된 생각이라고 생각하는 것이 안전합니까? –

0

QVariant 내에 저장된 포인터의 유형을 나중에 찾고 싶은 곳에서 비슷한 문제가 발생했습니다.

QVariant::canConvert<ModelBase*>을 사용하면 나중에 포인터의 유형을 결정할 수 있으므로 기본값 void* 대신 입력 된 포인터를 선언하는 것이 유용 할 수 있습니다.