Access to a pimpl's members from another pimpl I am writing an audio engine that must be multi-platform (win/linux). Basically, a CSound represents a sound file, and CSoundInstance represents one playing of a CSound. Obviously, playing sound is very different on Windows than it is on linux.

A CSoundInstance needs access to some data from its corresponding CSound. The data is heavily implementation-dependent and cannot really be abstracted.

Here are the API headers for the two classes. I omitted operator= overloads / unique_ptr use etc.

API/Sound.hpp

class CSound
{
public: 
    CSound(...file...);
    ~CSound();
private: 
    CSoundImpl *impl;
};


API/SoundInstance.hpp

class CSoundInstance
{
public:
    CSoundInstance(CSound *); // going to need access to source voice buffer
    ~CSoundInstance();
    Play();
private:
    CSoundInstanceImpl *impl;
};


I guess it is clear where this is going. You would first instanciate a CSound, then acquire a CSoundInstance and Play it.

I Intend to have a specific XXImpl class for each system and platform. Under Windows, I use XAudio2, which needs several members in CSoundImpl (buffer + waveform descriptor), as well as CSoundInstanceImpl (voice + fx + sends + callbacks).



Here are the problems that I had using the pimpl idiom:

To play a sound, a CSoundInstanceImpl ultimately needs a reference to a CSoundImpl, on Windows and linux, but I cannot write this constructor:

CSoundInstance::CSoundInstance(CSound *sound)
    : impl(sound-&gt;impl)
{
    ...
}


Not only is sound-&gt;impl private, but it would also mess up unique_ptr use.

Another thing I tried is not using the constructor CSoundInstance(CSound *) at all, and adding a factory method with the signature CSoundInstance CSound::CreateInstance(), like this:

CSoundInstance CSound::CreateInstance()
{
    return this-&gt;impl-&gt;CreateInstance();
}

CSoundInstance CSoundImpl::CreateInstance()
{
    // here I have access to the CSoundImpl instance, that I need: this
    CSoundInstance instance(this);
}


But that would imply that I have this constructor:

CSoundInstance::CSoundInstance(CSoundImpl *soundImpl)
    : impl(new CSoundInstanceImpl(soundImpl))
{
    ...
}


Using a pointer to an implementation in the constructor of a non-implementation API class doesn't look right to me.

Maybe pimpl is not the right thing for this? Is there a way how I could tackle this problem better?
As you said, if you need something in a pimpl class from another class, then something is wrong. If you can't abstract away the differences, then you can't hide the differences and shouldn't use this idiom.

Don't you think it would be simpler to put Play() in CSound? Each version (Linux/Windows) would have its own pimpl and there would be no need to try to find an abstraction or to try to access private data. Otherwise it gets a bit messy, since your Linux/Windows implementations of CSoundInstances will need to accept only the correct implementation: I don't know how easy it is to do this at compile time.