2015-10-29 7 views
0

Я реализовал свой класс, скажем, класс A, используя стандартную идиому PIMPL.
Проблемы возникает, когда я пытаюсь перегрузкой << оператора для моего класса реализации AImplПроблема доступности идиомы PIMPL

/* 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.
Теперь я вхожу в дилемму о том, как я должен это решить. Один из способов - объявить перегруженного друга оператора класса A. Другой способ - сделать частное объявление класса AImpl общедоступным.

Какой подход лучше и безопаснее?

+0

Да еще один способ определить 'operator <<' внутри 'AImpl', а не просто объявить его. В любом случае, чаще всего с помощью pImpl класс «Impl» лучше всего помещается в «A.cpp», и нет никакой пользы и значительной многословности от сохранения разглашений деклараций и определений. –

+0

Это для сериализации или печати? Обычно вы не хотите печатать частные части своего класса, поэтому вам нужен только оператор << для A, который даже не должен быть другом. – MikeMB

+0

Как/почему у вас есть доступ к {{AImpl}} в любом месте, кроме {{A.cpp}}? –

ответ

1

ИМХО, вы злоупотребляете идиомой PIMPL. Идиома требует, чтобы реализация была действительно частной, то есть AImpl не следует определять в файле заголовка (для всех, чтобы видеть), скорее это должно быть определено в A.cpp, где также принадлежит оператор <<.

Если вы это сделаете, то оператор << бессмысленно объявлять в заголовочном файле, так как вы могли бы получить доступ к PIMPL, так или иначе, с помощью класса. Вместо этого вы должны определить ostream &operator <<(ostream &os, const A &obj) и сделать это friend из A.

Обратите внимание, что при таком подходе AImpl не должен ограничивать доступ. Это поле и размер будут доступны только от A.cpp. Но если вы хотите сделать внутренности AImpl be private, вы можете сделать ostream &operator <<(ostream &os, const A &obj) a friedAImpl.

/* 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; 
    ... 
} 
+0

Прошу прощения, потому что я недостаточно четко формулирую свою проблему. Я хотел перегрузить '<<' оператор для 'A' и' AImpl', поэтому я мог бы определить оператор для 'A', используя оператор для' AImpl'. Также я забыл упомянуть, что * AImpl.h * был закрытым заголовком, а не публичным, поэтому я не думаю, что я злоупотребляю PIMPL. Однако наилучшим решением является перегрузка только оператора для основного класса, который я выяснил около 10 минут после публикации этого вопроса. Который, кажется, и ваше решение. – Kijan

+0

@Kijan Вы все еще можете это сделать, но поскольку 'AImpl.h' является закрытым (только для' A.cpp'), содержимое файла заголовка скорее принадлежит 'A.cpp'). Оператору для 'AImpl', вероятно, не нужно будет обращаться к' A': обычно в pipml нет ссылки на содержащийся объект, и поэтому нет объекта 'A', на который' AImpl :: operator << 'хотел бы действуют на. – skyking

 Смежные вопросы

  • Нет связанных вопросов^_^