5

I use the pimpl idiom for classes in the public API of my library to benefit from it's properties like ABI stability. In my non-public code it would be convenient to have access to the impl object to directly operate on it.

Is it considered bad practice to add a getter to the API class to return the impl pointer? Why?

The client of my library couldn't use the impl obj anyway as its interface is non-public. My library internal code, on the other hand, can now operate on the impl obj.

public.h:

class PublicClass{
    struct Impl;
    Impl* m_impl;
public:
    Impl* getImpl();
};

impl.h:

struct Impl{
    int foo();
};

main.cpp:

#include "public.h"
#include "impl.h"

int main(){
    PublicClass p;
    auto pimpl = p.getImpl();
    auto interestingVal = pimpl->foo();
}

Just a design question.

Jus Gru
  • 106
  • 4
  • If internal code of your library (beyond just the implementation of `PublicClass`) can "make use" of its internal implementation details en masse, I'd argue your code is not partitioned well enough. – StoryTeller - Unslander Monica Nov 29 '22 at 08:19
  • The pimpl pattern is supposed to be a compilation firewall. The implementation is NOT supposed to leak out in any way. You will just have to forward each and every method explicitly (in the cpp file of PublicClass). If you don't want to do that create an abstract factory that can return an interface (abstract baseclass) to your implementation – Pepijn Kramer Nov 29 '22 at 08:21
  • I agree that letting the `Impl` leak sounds like a design problem. But if you *really* need one specific function or class to be able to access the `Impl`, then make that specific function or class a friend of `PublicClass` so that they (and only they) can reach in and get it themselves. – Frodyne Nov 29 '22 at 09:05
  • Exposing the private implementation though a header file (Impl.h here) and a getter function (`getImpl()` here) removes the data hiding advantage of using pimpl. It depends on whether it does matter for you or not. – Fareanor Nov 29 '22 at 10:42
  • Please see the section of [help/dont-ask](https://stackoverflow.com/help/dont-ask) on writing _constructive_ subjective questions. – starball Dec 21 '22 at 22:09

1 Answers1

0

As always, this depends on an exact situation. Some examples:

  • A very common case is when you need non-public access in unit-tests, to test some functionality that is not directly exposed to users. If this is the case, then go forward and obtain direct access to the impl. (Although in this particular case you probably can just write unit-tests for Impl class itself.)
  • If there is a group of (a few) tightly coupled classes that actually serve as one "design-unit", then it is also OK to use getImpl between these classes. E.g. this may be class PublicService and class PublicClassRequest, and the request may need to access impl of the service, or vice versa.

However, if a lot of different classes depend on your getImpl, then you should rethink your design.

Basically, I would say that you should make your getImpl private, and then friend the users of getImpl, with the standard attitude to friends (see, e.g., https://isocpp.org/wiki/faq/friends#friends-and-encap).

Petr
  • 9,812
  • 1
  • 28
  • 52