PIMPL 成语可访问性问题

PIMPL idiom accessibility issue

本文关键字:问题 访问 成语 PIMPL      更新时间:2023-10-16

我已经实现了我的类,假设使用标准的 PIMPL 习语进行类A
当我尝试为我的实现类重载运算符时出现问题<< AImpl

/* A.h */
class A {
public:
     ...
private:
     class AImpl;
     AImpl *impl;
}
/* Aimpl.h */
class AImpl {
     ...
     friend ostream &operator <<(ostream &os, const AImpl &impl);
     ...
}
/* elsewhere.cpp */
ostream &operator <<(ostream &os, const AImpl &impl) {
     ...
}

问题源于重载运算符无法访问AImpl类,在 A 中声明为 private。
现在我有点进退两难,我应该如何解决这个问题。一种方法是声明类 A 的重载运算符朋友。另一种方法是公开阶级AImpl的私人声明。

哪种方法更好更安全?

恕我直言,您滥用了 PIMPL 习语。该习语要求实现真正私有,也就是说AImpl不应该在头文件中定义(供所有人查看(,而是应该在<<运算符所属的A.cpp中定义。

如果这样做,<<运算符在头文件中声明也是没有意义的,无论如何,您访问 PIMPL 的唯一方法是通过包含类。您可以改为定义ostream &operator <<(ostream &os, const A &obj)并将其作为Afriend

请注意,使用此方法,AImpl不需要对访问进行严格限制。无论如何,它的字段和大小只能从A.cpp获得。但是如果你想让AImpl的内部结构变得private你也可以让ostream &operator <<(ostream &os, const A &obj)成为AImplfried

/* A.h */
class A {
public:
     ...
private:
     class AImpl;
     AImpl *impl;
     friend ostream &operator <<(ostream &os, const A &obj);
}
/* A.cpp */
class AImpl {
public:
     // OR:
     friend ostream &operator <<(ostream &os, const A &obj);
     ...
}
ostream &operator <<(ostream &os, const A &obj) {
     AImpl* impl = obj.impl;
     ...
}