4

.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.

0xbaadf00d
  • 2,535
  • 2
  • 24
  • 46

3 Answers3

8

You can hide d behind an accessor function, and overload that based on const. Instead of accessing d directly, you then write impl()->count = 2;. impl() would return Private *, whereas impl() const would return const Private *.

  • Almost what I want. I'd still need to block direct access to the member variable. Good suggestion though! – 0xbaadf00d Nov 04 '13 at 14:03
  • 2
    @justanothercoder Rename it to `_d_dont_use_directly` and hit anyone who does use it directly with a stick. :) More seriously, you could make the member variable itself `const Private *`, and in the non-const `impl()` function, use `const_cast`. That should prevent accidental misuse.. –  Nov 04 '13 at 14:12
  • You also have to delete your copy constructor, otherwise you can copy a const XX into a non-const one, and then use the non-const member functoins. – Edward Z. Yang Sep 20 '17 at 00:46
  • @EdwardZ.Yang If `A` owns a `B`, then `A` should copy `B` in its copy constructor, and there's no problem that non-`const` member functions can be called on the copy. If `A` doesn't own `B` but merely holds a pointer or reference to it, then `A`'s `const`-ness probably shouldn't affect `B`'s. –  Sep 20 '17 at 01:13
  • With shared_ptr you can have multiple owning copies to logically the same resource. It's hard to justify why a const reference to the resource should be transformable into a non-const version, now. – Edward Z. Yang Sep 21 '17 at 00:41
2

.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()
{
    ...
}
0xbaadf00d
  • 2,535
  • 2
  • 24
  • 46
0

Instead of marking the entire class for export, only mark the functions you intend on using through the dll.

class myclass
{
public:
    DLLEXPORTMACROTHING myclass();
    DLLEXPORTMACROTHING ~myclass();

    DLLEXPORTMACROTHING void myfunction();
...
private:
    struct Private;
    PrivatePtr<Private> d;
};
Lambage
  • 367
  • 3
  • 8
  • I'm sorry but this is not relevant for the answer. I don't even know why I put the macro there, maybe there was some point or not, but I honestly cannot remember anymore. – 0xbaadf00d Jan 11 '17 at 08:54
  • I realized it wasn't an answer to the original question, but figured it would be nice to add this in. Maybe it would have been better as a comment... – Lambage Jan 12 '17 at 19:19