PIMPL习语无障碍问题

PIMPL idiom accessibility issue

我已经实现了我的 class,比方说 class A 使用标准的 PIMPL 习惯用法。
当我尝试为我的实现重载 << 运算符时出现问题 class 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 class,在 A.
中声明为私有 现在我对如何解决这个问题感到进退两难。一种方法是也声明 class A 的重载运算符友元。另一种方法是私有声明 class AImpl public.

哪种方法更好更安全?

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

如果你这样做,<< 运算符在头文件中声明也是毫无意义的,你访问 PIMPL 的唯一方法就是通过包含 class 的方法。您可以改为定义 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;
     ...
}