Custom Type Example

Contents:

Overview

Qt provides a range of standard value types that are used to provide rich and meaningful APIs. These types are integrated with the meta-object system, enabling them to be stored in QVariant objects, written out in debugging information and sent between components in signal-slot communication.

Custom types can also be integrated with the meta-object system as long as they are written to conform to some simple guidelines. In this example, we introduce a simple Message class, we describe how we make it work with QVariant, and we show how it can be extended to generate a printable representation of itself for use in debugging output.

The Message Class Definition

The Message class is a simple value class that contains two pieces of information (a QString and a QStringList), each of which can be read using trivial getter functions:

 
Sélectionnez
class Message
{
public:
    Message();
    Message(const Message &other);
    ~Message();

    Message(const QString &body, const QStringList &headers);

    QString body() const;
    QStringList headers() const;

private:
    QString m_body;
    QStringList m_headers;
};

The default constructor, copy constructor and destructor are all required, and must be public, if the type is to be integrated into the meta-object system. Other than this, we are free to implement whatever we need to make the type do what we want, so we also include a constructor that lets us set the type's data members.

To enable the type to be used with QVariant, we declare it using the Q_DECLARE_METATYPE() macro:

 
Sélectionnez
Q_DECLARE_METATYPE(Message);

We do not need to write any additional code to accompany this macro.

To allow us to see a readable description of each Message object when it is sent to the debug output stream, we define a streaming operator:

 
Sélectionnez
QDebug operator<<(QDebug dbg, const Message &message);

This facility is useful if you need to insert tracing statements in your code for debugging purposes.

The Message Class Implementation

The implementation of the default constructor, copy constructor and destructor are straightforward for the Message class:

 
Sélectionnez
Message::Message()
{
}

Message::Message(const Message &other)
{
    m_body = other.m_body;
    m_headers = other.m_headers;
}

Message::~Message()
{
}

The streaming operator is implemented in the following way:

 
Sélectionnez
QDebug operator<<(QDebug dbg, const Message &message)
{
    const QString body = message.body();
    QVector<QStringRef> pieces = body.splitRef("\r\n", QString::SkipEmptyParts);
    if (pieces.isEmpty())
        dbg.nospace() << "Message()";
    else if (pieces.size() == 1)
        dbg.nospace() << "Message(" << pieces.first() << ")";
    else
        dbg.nospace() << "Message(" <&