c++ - How to expose the implementation only to a specified set of classes in the pimpl idiom? -


let's have class a has inner class a::impl. class allowedtoaccess should able a::impl& class a, no other class should able or know class a::impl exists.

class a_1 { public:     class impl;      impl& impl();     const impl& impl() const;  private:     std::unique_ptr<impl> m_impl; };  class a_2 { private:     friend class allowedtoaccess;      class impl;     std::unique_ptr<impl> m_impl; };  class a_3 { private:     friend class allowedtoaccess;      class impl;      class implcontainer     {         friend class a_3;         std::unique_ptr<impl> impl;     } m_implcontainer;      impl& impl(); // return *m_implcontainer.impl;     const impl& impl() const; // return *m_implcontainer.impl; }; 

here code illustrate ideas.

a_1

pros: m_impl secured.

cons: classes not supposed know a::impl know (although don't know a::impl about).

a_2

pros: classes not supposed know a::impl not know it.

cons: m_impl not secured (allowedtoaccess might set nullptr).

a_3

pros: classes not supposed know a::impl not know , m_impl secured.

cons: boilerplate code implcontainer.

any better ideas?

edit: came solution this.

template <typename t> class accessor { private:     friend class allowedtoaccess;      typedef typename t::impl impl_t;      static typename t::impl& impl(t& t)     {         return *t.m_impl;     }      static const typename t::impl& impl(const t& t)     {         return *t.m_impl;     } };  class { private:     friend class accessor<a>;      class impl;     std::unique_ptr<impl> m_impl; };  class a::impl { public:     void f() const     {      } };  class allowedtoaccess { public:     allowedtoaccess()     {         const a;          const accessor<a>::impl_t& impl = accessor<a>::impl(a);          impl.f();     } }; 

there implementation layer of code, , classes added friends accessor.

and further hide things accessor forward declared template <typename t> class accessor; in public code. , defined in private code.

i don't know if better idea, provide own implementation of allowedtoaccess, safely expose needed interface. call accessor.

class base{   double priv = 0; public:   friend class accessor; };  class accessor { public:   int& priv(base& b) { return b.priv; }; }; 

now classes can access exposed privates through accessor. semantics change bit though because use accessor.priv(b) = something have full control on exposed interface. think accessor in variation have static methods since accessed object passed anyways. semantics accessor::priv(b).

i guess variation of a_3 example, code moved friend class. not pollute a_ class.

another option provide own accessor class in form of simple wrapper.

class accessor { public:   accessor(base b) _b(b);   int priv() { return _b.priv; };   int priv(int val) { _b.priv = val; };   int& priv_r() { return _b.priv; }; private:   base& _b; }; 

the interface here customizable, , can access features like:

base b; accessor interface(b); interface.priv(42); 

you can make absolutely safe disallowing derive accessor (there tricks that), no-one can derive , screw objects via evil implementation of accessor. think little bit paranoid though.


Comments

Popular posts from this blog

android - Get AccessToken using signpost OAuth without opening a browser (Two legged Oauth) -

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: mockito -

google shop client API returns 400 bad request error while adding an item -