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