Policies/Library Code Policy/Shared D-Pointer Example: Difference between revisions

From KDE TechBase
(→‎The .cpp file: Use smart pointer)
(Add note about QScopedPointer for d-pointers)
 
(One intermediate revision by one other user not shown)
Line 1: Line 1:
The following example illustrates the [[Policies/Library_Code_Policy#Shared D-Pointers|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.
The following example illustrates the [[Policies/Library_Code_Policy#Shared D-Pointers|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 {{qt|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 {{qt|QScopedPointer}}, otherwise your d_ptr will leak.


== The header file, without Q_DECLARE_PRIVATE ==
== The header file, without Q_DECLARE_PRIVATE ==
Line 12: Line 12:
     int someInteger() const;
     int someInteger() const;
protected:
protected:
     const QScopePointer<KFooBasePrivate> d_ptr;
     const QScopedPointer<KFooBasePrivate> d_ptr;
     KFooBase(KFooBasePrivate &dd, QObject *parent);
     KFooBase(KFooBasePrivate &dd, QObject *parent);
private:
private:
Line 50: Line 50:
     int someInteger() const;
     int someInteger() const;
protected:
protected:
     const QScopePointer<KFooBasePrivate> d_ptr;
     const QScopedPointer<KFooBasePrivate> d_ptr;
     KFooBase(KFooBasePrivate &dd, QObject *parent);
     KFooBase(KFooBasePrivate &dd, QObject *parent);
private:
private:
Line 91: Line 91:
}
}


// The destructor must be in the .cpp file, even if empty
KFooBase::~KFooBase()
KFooBase::~KFooBase()
{
{
Line 125: Line 126:
KFooDerived::KFooDerived(KFooDerivedPrivate &dd, QObject *parent)
KFooDerived::KFooDerived(KFooDerivedPrivate &dd, QObject *parent)
     : KFooBase(dd, parent)
     : KFooBase(dd, parent)
{
}
KFooDerived::~KFooDerived()
{
{
}
}

Latest revision as of 08:14, 7 January 2013

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;
}