Search code examples
c++pimpl-idiom

PIMPL const correctness


.h

public:
    void doStuff() const;
private:
    struct Private;
    Private * d;

.cpp

struct XX::Private
{
    int count;
}

void XX::doStuff() const
{
    d->count = 2; // I want an error here!!
}

Do you need furher explanation?

Update:

I thought I'd do something a bit different that requires less changes to the code. I made this:

.h

template <class TPriv>
class PrivatePtr
{
    public:
        ...
        TPriv * const operator->();
        TPriv const * const operator->() const;
        ...
    private:
        TPriv * m_priv;
};

.cpp

...

template <class TPriv>
TPriv * const PrivatePtr<TPriv>::operator->()
{
    return m_priv;
}

template <class TPriv>
TPriv const * const PrivatePtr<TPriv>::operator->() const
{
    return m_priv;
}

And then use it like this:

.h

#include <PrivatePtr.h>

class DLLEXPORTMACROTHING myclass
{
    ...
    private:
        struct Private;
        PrivatePtr<Private> d;
};

.cpp

#include <PrivatePtr.cpp>

struct myclass::Private()
{
    ...
}

But this causes C4251 "myclass::d : class 'PrivatePtr' needs to have dll-interface to be used by clients of clas 'myclass'

Wait, what? I DON'T want it to be used by anyone but myclass internally... safe to ignore? I tried looking for the answer but none of the cases were close to what I have here. On the other cases it did seems like quite a bit issue.


Solution

  • .h

    template <class TPriv>
    class PrivatePtr
    {
        public:
            ...
            TPriv * const operator->();
            TPriv const * const operator->() const;
            ...
        private:
            TPriv * m_priv;
    };
    

    .cpp

    ...
    
    template <class TPriv>
    TPriv * const PrivatePtr<TPriv>::operator->()
    {
        return m_priv;
    }
    
    template <class TPriv>
    TPriv const * const PrivatePtr<TPriv>::operator->() const
    {
        return m_priv;
    }
    

    And then use it like this:

    .h

    #include <PrivatePtr.h>
    
    class DLLEXPORTMACROTHING myclass
    {
        ...
        private:
            struct Private;
            PrivatePtr<Private> d;
    };
    

    .cpp

    #include <PrivatePtr.cpp>
    
    struct myclass::Private()
    {
        ...
    }