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

    From KDE TechBase
    (now...)
    (Add note about QScopedPointer for d-pointers)
     
    (9 intermediate revisions by 4 users 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 ==
    <code cppqt>
    <source lang="cpp-qt">
    class KFooBasePrivate;
    class KFooBasePrivate;
    class KFooBase : public QObject
    class KFooBase : public QObject
    Line 8: Line 8:
    public:
    public:
         KFooBase(QObject *parent);
         KFooBase(QObject *parent);
        ~KFooBase();
         void setSomeInteger(int i);
         void setSomeInteger(int i);
         int someInteger() const;
         int someInteger() const;
    protected:
    protected:
         KFooBasePrivate * const d_ptr;
         const QScopedPointer<KFooBasePrivate> d_ptr;
         KFooBase(KFooBasePrivate &dd, QObject *parent);
         KFooBase(KFooBasePrivate &dd, QObject *parent);
    private:
    private:
    Line 24: Line 25:
    public:
    public:
         KFooDerived(QObject *parent);
         KFooDerived(QObject *parent);
        void setAnotherInteger(int i);
        int anotherInteger() const;
         int sumOfIntegers() const;
         int sumOfIntegers() const;
    protected:
    protected:
    Line 30: Line 33:
         friend class KFooDerivedPrivate;
         friend class KFooDerivedPrivate;
         inline KFooDerivedPrivate *d_func()
         inline KFooDerivedPrivate *d_func()
         { return reinterpret_cast<KFooDerivedPrivate *>(d_ptr); }
         { return reinterpret_cast<KFooDerivedPrivate *>(d_ptr.data()); }
         inline const KFooDerivedPrivate *d_func() const
         inline const KFooDerivedPrivate *d_func() const
         { return reinterpret_cast<KFooDerivedPrivate *>(d_ptr); }
         { return reinterpret_cast<KFooDerivedPrivate *>(d_ptr.data()); }
    };
    };
    </code>
    </source>


    == The header file, with Q_DECLARE_PRIVATE ==
    == The header file, with Q_DECLARE_PRIVATE ==
    <code cppqt>
    <source lang="cpp-qt">
    class KFooBasePrivate;
    class KFooBasePrivate;
    class KFooBase : public QObject
    class KFooBase : public QObject
    Line 43: Line 46:
    public:
    public:
         KFooBase(QObject *parent);
         KFooBase(QObject *parent);
        ~KFooBase();
         void setSomeInteger(int i);
         void setSomeInteger(int i);
         int someInteger() const;
         int someInteger() const;
    protected:
    protected:
         KFooBasePrivate * const d_ptr;
         const QScopedPointer<KFooBasePrivate> d_ptr;
         KFooBase(KFooBasePrivate &dd, QObject *parent);
         KFooBase(KFooBasePrivate &dd, QObject *parent);
    private:
    private:
    Line 57: Line 61:
    public:
    public:
         KFooDerived(QObject *parent);
         KFooDerived(QObject *parent);
        void setAnotherInteger(int i);
        int anotherInteger() const;
         int sumOfIntegers() const;
         int sumOfIntegers() const;
    protected:
    protected:
    Line 63: Line 69:
         Q_DECLARE_PRIVATE(KFooDerived)
         Q_DECLARE_PRIVATE(KFooDerived)
    };
    };
    </code>
    </source>


    == The .cpp file ==
    == The .cpp file ==
    <code cppqt>
    <source lang="cpp-qt">
    /*** KFooBase ***/
    /*** KFooBase ***/
    class KFooBasePrivate
    class KFooBasePrivate
    Line 85: Line 91:
    }
    }


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


    Line 93: Line 99:
    {
    {
         Q_D(KFooBase);
         Q_D(KFooBase);
         d->someInteger = i;
         d->someInteger = i;
    }
    }
    Line 98: Line 105:
    int KFooBase::someInteger() const
    int KFooBase::someInteger() const
    {
    {
         // because of 'const' use d_func here instead of Q_D
         // in const functions add 'const' to the class name
         return d_func()->someInteger;
        Q_D(const KFooBase);
     
         return d->someInteger;
    }
    }


    Line 120: Line 129:
    }
    }


    KFooDerived::~KFooDerived()
    void KFooDerived::setAnotherInteger(int i)
    {
        Q_D(KFooDerived);
     
        d->anotherInteger = i;
    }
     
    int KFooDerived::anotherInteger() const
    {
    {
         /* no need to delete the d-pointer! */
         // in const functions add 'const' to the class name
        Q_D(const KFooDerived);
     
        return d->anotherInteger;
    }
    }


    int KFooDerived::sumOfIntegers() const
    int KFooDerived::sumOfIntegers() const
    {
    {
         return d_func()->someInteger + d_func()->anotherInteger;
         // in const functions add 'const' to the class name
        Q_D(const KFooDerived);
     
        return d->someInteger + d->anotherInteger;
    }
    }
    </code>
    </source>

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