




Вы можете создать конструктор private, а затем предоставить статический фабричный метод public для создания объектов.
Один из способов сделать это - сделать конструкторы закрытыми и разрешить построение только с помощью статического метода, возвращающего указатель. Например:
class Foo
{
public:
~Foo();
static Foo* createFoo()
{
return new Foo();
}
private:
Foo();
Foo(const Foo&);
Foo& operator=(const Foo&);
};
Или еще лучше статическая функция, которая возвращает std :: unique_ptr <Foo>.
Но зачем делать его и непередаваемым?
Потому что, если он выделен в куче, объект не должен копироваться, должен быть скопирован только его указатель.
Вы можете создать файл заголовка, который предоставляет абстрактный интерфейс для объекта, и фабричные функции, возвращающие указатели на объекты, созданные в куче.
// Header file
class IAbstract
{
virtual void AbstractMethod() = 0;
public:
virtual ~IAbstract();
};
IAbstract* CreateSubClassA();
IAbstract* CreateSubClassB();
// Source file
class SubClassA : public IAbstract
{
void AbstractMethod() {}
};
class SubClassB : public IAbstract
{
void AbstractMethod() {}
};
IAbstract* CreateSubClassA()
{
return new SubClassA;
}
IAbstract* CreateSubClassB()
{
return new SubClassB;
}
В случае C++ 11
class Foo
{
public:
~Foo();
static Foo* createFoo()
{
return new Foo();
}
Foo(const Foo &) = delete; // if needed, put as private
Foo & operator=(const Foo &) = delete; // if needed, put as private
Foo(Foo &&) = delete; // if needed, put as private
Foo & operator=(Foo &&) = delete; // if needed, put as private
private:
Foo();
};
Как сказал Скотт Мейерс в «Правиле 11: Предпочитайте удаленные функции частным неопределенным». В своей книге «Эффективный современный C++» лучше объявить удаленные функции-члены public. --QUOTE-- «По соглашению, удаленные функции объявляются public, а не private. Для этого есть причина. Когда клиентский код пытается использовать функцию-член, C++ проверяет доступность перед удаленным статусом. Когда клиентский код пытается использовать удалена функция private, некоторые компиляторы жалуются только на то, что эта функция является private, хотя доступность функции не влияет на возможность ее использования ».
--QUOTE-- «Это стоит иметь в виду при пересмотре устаревшего кода, чтобы заменить функции-члены private и не определенные функции-члены удаленными, потому что создание новых функций public обычно приводит к более качественным сообщениям об ошибках».
Должен. Дайте. Моар. Вверх. Голоса.
Следующее разрешает общедоступные конструкторы и остановит выделение стека, выбрасывая во время выполнения. Примечание thread_local - это ключевое слово C++ 11.
class NoStackBase {
static thread_local bool _heap;
protected:
NoStackBase() {
bool _stack = _heap;
_heap = false;
if (_stack)
throw std::logic_error("heap allocations only");
}
public:
void* operator new(size_t size) throw (std::bad_alloc) {
_heap = true;
return ::operator new(size);
}
void* operator new(size_t size, const std::nothrow_t& nothrow_value) throw () {
_heap = true;
return ::operator new(size, nothrow_value);
}
void* operator new(size_t size, void* ptr) throw () {
_heap = true;
return ::operator new(size, ptr);
}
void* operator new[](size_t size) throw (std::bad_alloc) {
_heap = true;
return ::operator new[](size);
}
void* operator new[](size_t size, const std::nothrow_t& nothrow_value) throw () {
_heap = true;
return ::operator new[](size, nothrow_value);
}
void* operator new[](size_t size, void* ptr) throw () {
_heap = true;
return ::operator new[](size, ptr);
}
};
bool thread_local NoStackBase::_heap = false;
Я не думаю, что вам нужен _stack в качестве члена данных. Достаточно иметь его как простую переменную стека внутри конструктора NoStackBase.
Также не нужно делать деструктор virtual. В любом случае никто не может удалить производный класс через NoStackBase.
поскольку вы явно вызываете глобальный оператор new, я предполагаю, что это не вызовет перегрузки какого-либо настраиваемого оператора, которые определены этими объектами (?), и принуждение к их использованию может быть мотивирующей причиной для этого вопроса
Это должно быть возможно в C++ 20 с использованием разрушающего оператора delete, см. p0722r3.
#include <new>
class C
{
private:
~C() = default;
public:
void operator delete(C *c, std::destroying_delete_t)
{
c->~C();
::operator delete(c);
}
};
Обратите внимание, что частный деструктор не позволяет использовать его ни для чего другого, кроме продолжительности динамического хранения. Но разрушающий оператор delete позволяет уничтожить его с помощью выражения удаления (поскольку выражение удаления неявно не вызывает деструктор в этом случае).
Обратное, что тоже может быть интересно читателям: stackoverflow.com/questions/10985/…