c++ - q_property - qt read write notify




QObject에서 파생 된 클래스에서 qRegisterMetaType을 올바르게 사용하는 방법? (2)

다음은 Qt 5의 Chris '솔루션 # 2에 대한 업데이트입니다.

namespace QtMetaTypePrivate {
    template <>
    struct QMetaTypeFunctionHelper<ClassA, true> {
        static void Delete(void *t)
        {
            delete static_cast<ClassA*>(t);
        }

        static void *Create(const void *t)
        {
            Q_UNUSED(t)
            return new ClassA();
        }

        static void Destruct(void *t)
        {
            Q_UNUSED(t) // Silence MSVC that warns for POD types.
            static_cast<ClassA*>(t)->~ClassA();
        }

        static void *Construct(void *where, const void *t)
        {
            Q_UNUSED(t)
            return new (where) ClassA;
        }
    #ifndef QT_NO_DATASTREAM
        static void Save(QDataStream &stream, const void *t)
        {
            stream << *static_cast<const ClassA*>(t);
        }

        static void Load(QDataStream &stream, void *t)
        {
            stream >> *static_cast<ClassA*>(t);
        }
    #endif // QT_NO_DATASTREAM
    };
}

ClassA가 QDataStream에 대해 연산자 << 및 연산자 >>를 지원하지 않으면 저장 및로드 본문을 주석 처리하십시오. 그렇지 않으면 컴파일러 오류가 발생합니다.

나는 이것에 대한 답변을 찾기 위해 광범위하게 검색했지만 아무 소용이 없습니다. 나의 애도는 다음과 같습니다.

나는 대략 다음과 같은 ClassA 를 가지고있다.

class ClassA : public QObject {
    Q_OBJECT
public:
    ClassA() { mName = "lol"; }
    ~ClassA();
    void ShowName() { std::cout << mName << std::endl; }
    std::string mName;
};

물론 moc을 사용하기 때문에이 클래스는 실제로 프로젝트에서 cpp와 hpp로 나뉘지만 여기서는 문제가 아닙니다.

Q_DECLARE_METATYPE 은 실제로 그 기능 (QVariant 확장)이 필요하지 않으므로 사용하지 마십시오. 런타임 인스턴스화에만 관심이 있습니다.

여기서 문제는 Q_OBJECT 가 복사 및 할당 생성자를 금지한다는 것입니다. 그 때문에, 나는 qRegisterMetaTypeClassA 자체가 아니라 ClassA* 에 적용해야합니다.이 qRegisterMetaType 는 처음에는 잘 작동하는 것으로 보입니다.

이제 런타임에서이 클래스를 문자열에서 동적으로 만들고 ShowName() 메서드를 실행하려고합니다. 나는 이렇게하고있다.

int main() {
    qRegisterMetaType<ClassA*>("ClassA*");

    int id = QMetaType::type("ClassA*");
    std::cout << "meta id: " << id << std::endl; // Outputs correct generated user id (not 0)

    ClassA* myclass = static_cast<ClassA*>(QMetaType::construct(id));
    myclass->ShowName(); // Segfaults, oh dear

    return 0;
}

자, 내 문제가 있습니다. 실제로 올바르게 구성된 객체가없는 것 같습니다.

클래스를 다음과 같이 변경하면 :

class ClassA : public QObject {
    Q_OBJECT
public:
    ClassA() { mName = "lol"; }
    ClassA(const ClassA& other) { assert(false && "DONT EVER USE THIS"); }
    ~ClassA();
    void ShowName() { std::cout << mName << std::endl; }
    std::string mName;
};

그러면 우리는 다음과 같이 프로그램을 변경할 수 있습니다.

int main() {
    qRegisterMetaType<ClassA>("ClassA");

    int id = QMetaType::type("ClassA");
    std::cout << "meta id: " << id << std::endl; // Outputs correct generated user id (not 0)

    ClassA* myclass = static_cast<ClassA*>(QMetaType::construct(id));
    myclass->ShowName(); // "lol", yay

    return 0;
}

당연히 필자는 위조 된 복사본 생성자를 사용할 수는 있지만 올바른 느낌이 들지 않으며 Qt는 그 점에 대해 제안하고 대신 QObjects에 대한 포인터 사용만을 제안합니다.

누구가 여기에서 틀린 것을 보는지? 또한, 나는 비슷한 문제가 있음을 알고 있지만, 아무도이 정확한 문제를 다루지 않습니다.


몇 가지:

  • ClassA * 등록이 작동하지 않는 이유는 construct () 호출이 실제 객체가 아닌 ClassA 객체에 대한 포인터를 구성하기 때문입니다.

  • QMetaType 문서에서 다음 인용문에 주목할 가치가 있습니다.

공용 기본 생성자, 공용 복사본 생성자 및 공용 소멸자가있는 모든 클래스 또는 구조체를 등록 할 수 있습니다.

  • qMetaTypeConstructHelper의 Qt 구현을 살펴보십시오.

    template <typename T>
    void *qMetaTypeConstructHelper(const T *t)
    {
        if (!t)
            return new T();
        return new T(*static_cast<const T*>(t));
    }
    

복사 생성자의 사용법을 기록하십시오. 이 경우 문제를 해결하는 데 두 가지 방법이 있습니다.

1) 복사 생성자를 제공합니다 (이미 완료했습니다).

2) 복사 생성자를 사용하지 않는 qMetaTypeConstructHelper의 특수화를 제공하십시오.

template <>
void *qMetaTypeConstructHelper<ClassA>(const ClassA *)
{
    return new ClassA();
}




reflection