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
Post a Comment