Сводка : стандарт C ++ может определять нотацию и поведение для "виртуальных конструкторов", которые достаточно интуитивны и не слишком сложны для поддержки компиляторами, но зачем вносить Стандартные изменения именно для этого, если функциональность уже может быть реализована с использованием create()
/ clone()
(см. ниже)? Это не так полезно, как многие другие языковые предложения в процессе разработки.
Обсуждение
Давайте постулируем механизм «виртуального конструктора»:
Base* p = new Derived(...);
Base* p2 = new p->Base(); // possible syntax???
В приведенном выше примере первая строка создает объект Derived
, поэтому таблица виртуальной диспетчеризации *p
может разумно предоставить «виртуальный конструктор» для использования во второй строке. (Десятки ответов на этой странице о том, что «объект еще не существует, поэтому виртуальное строительство невозможно» излишне близоруко сфокусированы на объекте, который будет построен.)
Во второй строке постулируется нотация new p->Base()
для запроса динамического выделения и построения по умолчанию другого Derived
объекта.
Примечания:
компилятор должен организовать распределение памяти перед вызовом конструктора - конструкторы обычно поддерживают автоматическое (неофициально "стек") выделение, статические (для глобальной области / области имен и объектов класса / функции- static
) и динамические (неофициально "куча") при использовании new
размер объекта, который должен быть построен с помощью p->Base()
, вообще не может быть известен во время компиляции, поэтому динамическое распределение - единственный подход, который имеет смысл
для динамического выделения он должен вернуть указатель, чтобы память могла быть delete
d позже.
постулированная запись в явном виде перечисляет new
, чтобы подчеркнуть динамическое размещение и тип результата указателя.
Компилятору потребуется:
- выясните, сколько памяти
Derived
необходимо, либо вызвав неявную функцию virtual
sizeof
, либо получив такую информацию через RTTI
- вызов
operator new(size_t)
для выделения памяти
- invoke
Derived()
с размещением new
.
OR
- создать дополнительную запись vtable для функции, которая сочетает в себе динамическое размещение и конструкцию
Итак - не кажется непреодолимым указывать и реализовывать виртуальные конструкторы, но вопрос на миллион долларов: как это будет лучше, чем то, что возможно при использовании существующих возможностей языка C ++ ...? Лично, Я не вижу никакой выгоды по сравнению с решением ниже.
`clone ()` и `create ()`
FAQ по C ++ документирует идиому «виртуального конструктора» , содержащую методы virtual
create()
и clone()
для создания по умолчанию или копирования-создания нового динамически размещаемого объекта:
class Shape {
public:
virtual ~Shape() { } // A virtual destructor
virtual void draw() = 0; // A pure virtual function
virtual void move() = 0;
// ...
virtual Shape* clone() const = 0; // Uses the copy constructor
virtual Shape* create() const = 0; // Uses the default constructor
};
class Circle : public Shape {
public:
Circle* clone() const; // Covariant Return Types; see below
Circle* create() const; // Covariant Return Types; see below
// ...
};
Circle* Circle::clone() const { return new Circle(*this); }
Circle* Circle::create() const { return new Circle(); }
Также возможно изменить или перегрузить create()
для приема аргументов, хотя для соответствия сигнатуре функции virtual
базового класса / интерфейса аргументы для переопределений должны точно соответствовать одной из перегрузок базового класса. С помощью этих явных пользовательских средств легко добавить ведение журнала, инструментарий, изменить распределение памяти и т. Д.