Implementing Value Object

Implementing a Qt friendly value object can be a bit cumbersome, but it is worth your time. A Qt value object can be stored in containers (such as lists or in hash values), can be used as hash keys, and stored inside QVariant.
Here's a working example for a custom Qt friendly value type.
The Contact class features the following:

Container Friendly Methods

  1. A default constructor
  2. A copy constructor
  3. An assignment operator

Hash Friendly Methods

  1. qHash
  2. Equality Operator

Developer Friendly Methods (Debug)

  1. The print-to-debug-stream operator
#ifndef CONTACT_H
#define CONTACT_H
#include <QString>
#include <QMetaType>

class Contact
{
public:
    // container friendly
    Contact();

    Contact(const Contact  &other);

    const Contact &operator=(const Contact &other);

    // hash friendly
    bool operator==(const Contact &other) const;

    Contact(const QString &name, const QString &phone);

    void setName(const QString &name);
    void setPhone(const QString &phone);

    const QString &getName() const;
    const QString &getPhone() const;

private:
    QString iName;
    QString iPhone;
};

// hash friendly
uint qHash( const Contact &key );

// debug friendly
QDebug operator<<(QDebug d, const Contact &contact);

Q_DECLARE_METATYPE(Contact);

#endif // CONTACT_H

#include "contact.h"
#include <QDebug>

Contact::Contact()
{
  // blank on purpose
}

Contact::Contact(const Contact  &other):
    iName ( other.iName ),
    iPhone ( other.iPhone )
{
  // blank on purpose
}

Contact::Contact(const QString &name, const QString &phone):
    iName ( name ),
    iPhone ( phone )
{
  // blank on purpose
}

const Contact &Contact::operator=(const Contact &other)
{
    iName = other.iName;
    iPhone = other.iPhone;
    return *this;
}


bool Contact::operator==(const Contact &other) const
{
    return ( ( getName() == other.getName() ) && ( getPhone() == other.getPhone() ) );
}

void Contact::setName(const QString &name)
{
    iName = name;
}

void Contact::setPhone(const QString &phone)
{
    iPhone = phone;
}


const QString &Contact::getName() const
{
    return iName;
}

const QString &Contact::getPhone() const
{
    return iPhone;
}

uint qHash( const Contact &key )
{
    uint result = 17;

    result = 31 * qHash(key.getName());
    result = 31 * qHash(key.getPhone());

    return result;
}


QDebug operator<<(QDebug d, const Contact &contact)
{
    d << contact.getName() << ':' << contact.getPhone();
    return d;
}


#include <QtCore/QString>
#include <QtTest/QtTest>
#include <QDebug>
#include <QVariant>
#include <QHash>
#include "contact.h"

class ValueObjectTest : public QObject
{
    Q_OBJECT

public:
    ValueObjectTest();

private Q_SLOTS:
    void initTestCase();
    void cleanupTestCase();

    void testDebug();
    void testHash();
    void testVariant();

private:
    QList<Contact> data;
};

ValueObjectTest::ValueObjectTest()
{
}

void ValueObjectTest::initTestCase()
{
    data << Contact("Foo", "03-9112020") << Contact("Bar", "04-6992030") << Contact("Buz", "077-8934121");
}

void ValueObjectTest::cleanupTestCase()
{
    data.clear();
}

void ValueObjectTest::testDebug()
{
    foreach (Contact c, data)
    {
        qDebug() << c;
    }
}

void ValueObjectTest::testHash()
{
    QHash<Contact, int> iLike;
    Contact c = data.at(0);
    Contact d = data.at(1);

    Contact c_c(c);

    iLike[c] = 10;
    iLike[d] = 15;
    iLike[c_c] = 8;

    QVERIFY(iLike[c]   == 8);
    QVERIFY(iLike[c_c] == 8);
    QVERIFY(iLike[d]   == 15);
}

void ValueObjectTest::testVariant()
{
    QVariant v;
    v.setValue(data.first());

    Contact c = v.value<Contact>();

    QVERIFY(c == data.first());
}

QTEST_APPLESS_MAIN(ValueObjectTest);

#include "tst_valueobjecttest.moc"