Domanda

Si consideri il seguente:

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>();
    };
};

Sembra DirectoryIterator dovrebbe essere in grado di chiamare boost::make_shared<DirectoryIteratorImpl>, perché è un amico di DirectoryIteratorImpl. Tuttavia, questo codice non riesce a compilare poiché il costruttore per DirectoryIteratorImpl è privato.

Dal momento che questa classe è un dettaglio interno di implementazione che i clienti di DirectoryIterator non dovrebbero mai toccare, sarebbe bello se potessi mantenere il costruttore privato.

E 'questo il mio equivoco fondamentale attorno make_shared o ho bisogno di segnare una sorta di pezzo spinta come friend in modo che la chiamata a compilare?

È stato utile?

Soluzione

sarà davvero bisogno di fare qualche amico pezzi spinta per questo. Fondamentalmente make_shared sta chiamando il costruttore e il fatto che questo viene fatto all'interno di una funzione amico non importa per il compilatore.

La notizia buona è però che make_shared chiama il costruttore, non qualsiasi altro pezzo. Quindi, solo facendo amico make_shared avrebbe funzionato ... Tuttavia ciò significa che chiunque potrebbe quindi creare un shared_ptr<DirectoryIteratorImpl> ...

Altri suggerimenti

C'è una ragione buona per non usare il buon vecchio costruttore shared_ptr? (Se c'è una, si potrebbe desiderare di dare un'occhiata al l'attuazione make_shared e farlo)

DirectoryIterator()
   : impl( new detail::DirectoryIteratorImpl() )
{}

In questo modo la chiamata al costruttore è fatto dalla classe DirectoryIterator che è già amico di DirectoryIteratorImpl senza aprire la porta per tutti gli altri codici.

È possibile suddividere la classe in parte di interfaccia e parte implementazione. La parte interfaccia è resa pubblica, e la parte implementazione può avere costruttori pubblici. Tuttavia, questo significa che devi utilizzare l'ereditarietà virtuale.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top