Policies/Library Code Policy/Shared D-Pointer Example

From KDE TechBase
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

The following example illustrates the shared d-pointer concept. The class presented here derives from QObject to illustrate parameter-passing in the constructor; it is not necessary to be like that in your code. This example puts your d-pointer into QScopedPointer which will handle proper deleting of the d-pointer once the main object is destroyed. Be sure to delete the d-pointer properly when not using QScopedPointer, otherwise your d_ptr will leak.

The header file, without Q_DECLARE_PRIVATE

class KFooBasePrivate;
class KFooBase : public QObject
{
public:
    KFooBase(QObject *parent);
    ~KFooBase();
    void setSomeInteger(int i);
    int someInteger() const;
protected:
    const QScopedPointer<KFooBasePrivate> d_ptr;
    KFooBase(KFooBasePrivate &dd, QObject *parent);
private:
    friend class KFooBasePrivate;
    inline KFooBasePrivate *d_func() { return d_ptr; }
    inline const KFooBasePrivate *d_func() const { return d_ptr; }
};

class KFooDerivedPrivate;
class KFooDerived : public KFooBase
{
public:
    KFooDerived(QObject *parent);
    void setAnotherInteger(int i);
    int anotherInteger() const;
    int sumOfIntegers() const;
protected:
    KFooDerived(KFooDerivedPrivate &dd, QObject *parent);
private:
    friend class KFooDerivedPrivate;
    inline KFooDerivedPrivate *d_func()
    { return reinterpret_cast<KFooDerivedPrivate *>(d_ptr.data()); }
    inline const KFooDerivedPrivate *d_func() const
    { return reinterpret_cast<KFooDerivedPrivate *>(d_ptr.data()); }
};

The header file, with Q_DECLARE_PRIVATE

class KFooBasePrivate;
class KFooBase : public QObject
{
public:
    KFooBase(QObject *parent);
    ~KFooBase();
    void setSomeInteger(int i);
    int someInteger() const;
protected:
    const QScopedPointer<KFooBasePrivate> d_ptr;
    KFooBase(KFooBasePrivate &dd, QObject *parent);
private:
    Q_DECLARE_PRIVATE(KFooBase)
};

class KFooDerivedPrivate;
class KFooDerived : public KFooBase
{
public:
    KFooDerived(QObject *parent);
    void setAnotherInteger(int i);
    int anotherInteger() const;
    int sumOfIntegers() const;
protected:
    KFooDerived(KFooDerivedPrivate &dd, QObject *parent);
private:
    Q_DECLARE_PRIVATE(KFooDerived)
};

The .cpp file

/*** KFooBase ***/
class KFooBasePrivate
{
public:
    virtual ~KFooBasePrivate() { }
    int someInteger;
};

KFooBase::KFooBase(QObject *parent) 
    : QObject(parent), d_ptr(new KFooBasePrivate)
{
}

KFooBase::KFooBase(KFooBasePrivate &dd, QObject *parent)
    : QObject(parent), d_ptr(&dd)
{
}

// The destructor must be in the .cpp file, even if empty
KFooBase::~KFooBase()
{
}

void KFooBase::setSomeInteger(int i)
{
    Q_D(KFooBase);

    d->someInteger = i;
}

int KFooBase::someInteger() const
{
    // in const functions add 'const' to the class name
    Q_D(const KFooBase);

    return d->someInteger;
}

/*** KFooDerived ***/

class KFooDerivedPrivate: public KFooBasePrivate
{
public:
    int anotherInteger;
};

KFooDerived::KFooDerived(QObject *parent)
    : KFooBase(*new KFooDerivedPrivate, parent)
{
}

KFooDerived::KFooDerived(KFooDerivedPrivate &dd, QObject *parent)
    : KFooBase(dd, parent)
{
}

void KFooDerived::setAnotherInteger(int i)
{
    Q_D(KFooDerived);

    d->anotherInteger = i;
}

int KFooDerived::anotherInteger() const
{
    // in const functions add 'const' to the class name
    Q_D(const KFooDerived);

    return d->anotherInteger;
}

int KFooDerived::sumOfIntegers() const
{
    // in const functions add 'const' to the class name
    Q_D(const KFooDerived);

    return d->someInteger + d->anotherInteger;
}