让我们有一个class A
它有一个内部 class A::Impl
. class AllowedToAccess
应该能够得到 A::Impl&
来自 class A
,没有其他类(class)应该能够做到这一点,甚至不知道 class A::Impl
存在。
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;
};
下面是一些代码来说明我的想法。
A_1
优点:m_impl
是安全的。
缺点:类不应该知道 A::Impl
会知道它(虽然他们不知道 A::Impl
到底是什么)。
A_2
优点:类不应该知道 A::Impl
不会知道的。
缺点:m_impl
不安全( AllowedToAccess
可能只是将其设置为 nullptr
)。
A_3
优点:类不应该知道 A::Impl
不会知道它和m_impl
是安全的。
缺点:ImplContainer
的样板代码.
有什么更好的主意吗?
编辑:提出了这样的解决方案。
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 A
{
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 a;
const Accessor<A>::impl_t& impl = Accessor<A>::impl(a);
impl.f();
}
};
有一个代码实现层,所有这些类都将作为 friend 添加到 Accessor。
并且为了进一步隐藏访问器只会被前向声明为 template <typename T> class Accessor;
的东西在公共(public)代码中。并在私有(private)代码中定义。
最佳答案
如果可以将与 m_impl 本身一起工作的所有逻辑移动到基类,则可以使派生类无法访问 m_impl,但允许它获得对 Impl
的引用,然后使 Access
类成为派生类的友元:
class Base {
protected:
class Impl;
Impl& impl();
private:
std::unique_ptr<Impl> m_impl;
};
class Base::Impl {
public:
Impl() {}
};
Base::Impl& Base::impl() { return *m_impl; }
class Derived : private Base {
public:
friend class Access;
Derived() {
auto& ptr = impl(); // ok
auto& ptr1 = m_impl; // error
}
};
class Access {
public:
Access(Derived& d) {
auto& ptr = d.impl(); // ok
auto& ptr1 = d.m_impl; // error
}
};
关于c++ - 如何仅将实现公开给 pimpl 习语中的一组指定类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22611210/