Я пишу абстрактный класс, и от него будут унаследованы многие другие классы. Абстрактный класс наследуется от класса std::enable_shared_from_this
. На странице примера cppreference лучший способ работать с этим — удалить общедоступный конструктор:
class Best : public std::enable_shared_from_this<Best>
{
struct Private{ explicit Private() = default; };
public:
// Constructor is only usable by this class
Best(Private) {}
// Everyone else has to use this factory function
// Hence all Best objects will be contained in shared_ptr
static std::shared_ptr<Best> create()
{
return std::make_shared<Best>(Private());
}
std::shared_ptr<Best> getptr()
{
return shared_from_this();
}
};
Как заставить людей, которые будут реализовывать мой абстрактный класс, сделать конструктор закрытым, но объявить «статическую фабричную функцию». Или, может быть, есть другой способ подсказать людям, которые будут реализовывать абстрактный класс, как правильно это сделать (кроме комментариев). В С++ нет виртуальных статических функций :(
@user12002570 user12002570 спасибо, я отредактировал вопрос, чтобы быть более точным :)
Вы не можете помешать людям отстреливаться, особенно в C++. Задокументируйте свой класс, сделайте акцент на том, что он использует std::enable_shared_from_this
и должен использоваться внутри std::shared_ptr
, возможно, добавьте пример использования фабричного метода в производном классе и доверьтесь своим коллегам.
ваш подход ошибочен. Как только тип появляется в сигнатуре общедоступного метода, он становится общедоступным. Использовать тип извне неудобно, но не невозможно (например, «невозможно, потому что он частный»). Если вы хотите сделать это невозможным, вам следует сделать Best
конструктор приватным.
с другой стороны, вы уже подталкиваете пользователей использовать статическую функцию. Также производный класс должен будет сконструировать Best
@ 463035818_is_not_an_ai Это не мой код, а код со страницы примера cppreference, я прикрепил ссылку к своему вопросу :)
В вашей текущей реализации есть несколько проблем:
Private
находится в приватном разделе, мы все равно можем создать его, если не используем его имя явно:struct ToAny
{
template <typename T>
requires (std::is_default_constructible_v<T>)
operator T() const { return T{}; } // Can construct `Private`
};
ToAny
, производные классы могут использовать конструктор Best
ограниченным образом: они не могут писать Private
, поэтому единственное решение — наследовать от Best конструктораclass Derived : public Best
{
public:
using Best::Best;
// Derived(int) : Best(ToAny{}) {}
};
Но создание Derived
(если ToAny
невозможно)
Вы можете изменить свой фабричный метод, чтобы разрешить также создание производных:
template <std::derived_from<Best> T>
static std::shared_ptr<T> create()
{
return std::make_shared<T>(Private());
}
Есть еще неудобства, так как производные классы не могут иметь лишних параметров.
Итак, исправим идиому пароля (Private
): сделайте его общедоступным с помощью частного конструктора и друга Base;
И настройте фабрику так, чтобы она принимала дополнительный параметр:
class Best : public std::enable_shared_from_this<Best>
{
public:
class Key{
private:
friend Best;
explicit Key() {}
};
// Constructor is only usable by this class
Best(Key) {}
// Everyone else has to use this factory function
// Hence all Best objects will be contained in shared_ptr
template <std::derived_from<Best> T, typename...Ts>
static std::shared_ptr<T> create(Ts&&...args)
{
return std::make_shared<T>(Key(), std::forward<Ts>(args)...);
}
// ..
};
Спасибо за ответ, хотя это не мой код с закрытым ключом, это правильный ответ на вопрос. Проблема здесь в том, что Key
затрудняет чтение кода. Это какой-то способ сделать код красивее, но в то же время заставить все Derived не иметь общедоступных конструкторов, а код должен быть таким же коротким, как здесь godbolt.org/z/35n8P98Wo ?
Я не думаю, что есть более короткая альтернатива.
Спасибо, принимаю ваш ответ)
Конструктор не может быть статическим в C++. По определению они являются нестатическими функциями-членами.