Рассмотрите следующее:
class DirectoryIterator;
namespace detail {
class FileDataProxy;
class DirectoryIteratorImpl
{
friend class DirectoryIterator;
friend class FileDataProxy;
WIN32_FIND_DATAW currentData;
HANDLE hFind;
std::wstring root;
DirectoryIteratorImpl();
explicit DirectoryIteratorImpl(const std::wstring& pathSpec);
void increment();
bool equal(const DirectoryIteratorImpl& other) const;
public:
~DirectoryIteratorImpl() {};
};
class FileDataProxy //Serves as a proxy to the WIN32_FIND_DATA struture inside the iterator.
{
friend class DirectoryIterator;
boost::shared_ptr<DirectoryIteratorImpl> iteratorSource;
FileDataProxy(boost::shared_ptr<DirectoryIteratorImpl> parent) : iteratorSource(parent) {};
public:
std::wstring GetFolderPath() const {
return iteratorSource->root;
}
};
}
class DirectoryIterator : public boost::iterator_facade<DirectoryIterator, detail::FileDataProxy, std::input_iterator_tag>
{
friend class boost::iterator_core_access;
boost::shared_ptr<detail::DirectoryIteratorImpl> impl;
void increment() {
impl->increment();
};
bool equal(const DirectoryIterator& other) const {
return impl->equal(*other.impl);
};
detail::FileDataProxy dereference() const {
return detail::FileDataProxy(impl);
};
public:
DirectoryIterator() {
impl = boost::make_shared<detail::DirectoryIteratorImpl>();
};
};
Кажется, что DirectoryIterator должен смочь звонить boost::make_shared<DirectoryIteratorImpl>
, потому что это - друг DirectoryIteratorImpl
. Однако этому коду не удается скомпилировать, потому что конструктор для DirectoryIteratorImpl является частным.
Так как этот класс является внутренней деталью реализации это клиенты DirectoryIterator
никогда не должен затрагивать, было бы хорошо, если я мог бы сохранить конструктора частным.
Это мое фундаментальное недоразумение вокруг make_shared
или сделайте я должен отметить своего рода часть повышения как friend
для вызова для компиляции?
Для этого вам действительно нужно подружиться с некоторыми элементами усиления. В основном make_shared
вызывает конструктор, и тот факт, что это делается из дружественной функции, не имеет значения для компилятора.
Хорошая новость заключается в том, что make_shared
вызывает конструктор, а не какой-либо другой компонент. Так что просто создание друга make_shared
будет работать ... Однако это означает, что любой может затем создать shared_ptr
...
Есть ли веская причина не использовать старый добрый конструктор shared_ptr
? (Если он есть, вы можете взглянуть на реализацию make_shared
и сделать это)
DirectoryIterator()
: impl( new detail::DirectoryIteratorImpl() )
{}
Таким образом, вызов конструктора выполняется из класса DirectoryIterator
, который уже является другом DirectoryIteratorImpl
, не открывая двери для всего остального кода.