Получение класса с помощью статического метода (aka. Factory), созданного с помощью базового класса. - PullRequest
1 голос
/ 27 января 2012

Я хочу сделать некоторые классы, которые будут иметь закрытые / защищенные конструкторы и будут иметь статический метод с именем create(). Позвольте мне показать вам код:

template <class T>
struct ServicePtr
{
    std::shared_ptr<T> service;
};

template <class T>
struct ServicePtrDeleter
{
    void operator()(T* ref) const
    {
        if (ref->service.get())
        {
        }

        delete ref;
    }
};

template <typename T>
struct ServiceCreator
{
    static std::shared_ptr< ServicePtr<T> > create()
    {
        std::shared_ptr< ServicePtr<T> > servicePtr(new ServicePtr<T>);
        servicePtr->service.reset(new T);
        return servicePtr;
    }
};

class S:public IService,
public ServiceCreator<S>
{
    protected:
    S()
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }

    public:
    virtual ~S()
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }
};

int main()
{
    auto s=S::create();
    return 0;
}

При компиляции с GCC 4.6.1 мне выдается следующая ошибка:

main.cc: В статической функции-члене 'static std :: shared_ptr> ServiceCreator :: create () [с T = S]':
main.cc:310:12: создается отсюда
main.cc:275:3: ошибка: 'S :: S ()' защищен
main.cc:177:3: ошибка: в этом контексте
make: * [main.o] Ошибка 1

Ответы [ 2 ]

1 голос
/ 27 января 2012

В ServiceCreator::create() вы делаете это:

servicePtr->service.reset(new T);

Если T равно S, это попытается создать S, но не удастся, поскольку S имеет защищенный конструктор.Чтобы позволить несвязанному классу получить доступ к этому конструктору, сохраняя при этом его защиту, вы должны сделать класс создателя (или просто функцию-член, которой требуется доступ) другом:

friend ServiceCreator<S>::create;
0 голосов
/ 27 января 2012

Основная проблема в том, что ServiceCreator<T>::create() попытается создать S здесь:

static std::shared_ptr< ServicePtr<T> > create()
{
    // ...
    servicePtr->service.reset(new T); // T = class S
    return servicePtr;
}

Но, конечно, он не может этого сделать, потому что конструктор class S защищен! Простой способ исправить это - просто сделать ServiceCreator другом S:

class S : public IService, public ServiceCreator<S>
{
  friend class ServiceCreator<S>;
  // ...
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...