#новичкам
Виртуальные методы - это основа полиморфизма, одного из важнейших концептов объектно-ориентированного программирования, который позволяет нам реализовывать сложные конструкции из классов и строить гибкую-расширяемую архитектуру. Но вот если на секунду задуматься: конструктор - это ведь тоже метод. Можем ли мы сделать конструктор класса виртуальным?
Один из тех самых популярных вопросов на собеседованиях, который не проверяет никаких практически применимых знаний. Он скорее направлен больше на понимание концепции ООП и механизма создания объектов в С++.
Ответ: нет, не можем. Логика тут довольно простая. Виртуальные функции подразумевают собой позднее связывание объекта и вызываемого метода в рантайме. То есть для них нужны объекты(точнее vptr, которых находится внутри них). А объекты создаются в рантайме. И для создания объектов нужны констукторы. Получается, если бы конструкторы были виртуальными, то
Если более формально и официально, то вот комментарий самого Бъерна по этому вопросу:
A virtual call is a mechanism to get
work done given partial information.
In particular, "virtual" allows us to
call a function knowing only an interfaces
and not the exact type of the object.
To create an object you need complete
information. In particular, you need to
know the exact type of what you want to
create. Consequently, a
"call to a constructor" cannot be virtual.
Виртуальный вызов — это механизм выполнения работы при наличии частичной информации. В частности, он позволяет нам вызывать функцию, зная только тип базового класса, а не точный тип объекта. Для создания объекта необходима полная информация. В частности, вам необходимо знать точный тип того, что вы хотите создать. Следовательно, «вызов конструктора» не может быть виртуальным.
Однако, нам по сути этого и не нужно. Нам нужен механизм создания объекта, зависящий от типа полиморфного объекта. И у нас такой механизм есть! Называется он фабричным методом. В ту же степь идет и паттерн "метод clone()".
В сущности, фабричный метод позволяет создавать объекты, тип которых зависит от типа объекта, у которого вызывается метод.
Метод clone позволяет создавать объекты именно того класса, который на самом деле лежит под данным указателем или ссылкой.
Выглядит это так:
class Shape {
public:
virtual ~Shape() { } // A virtual destructor
// ...
virtual std::unique_ptr<Shape> clone() const = 0; // Uses the copy constructor
virtual std::unique_ptr<Shape> create() const = 0; // Uses the default constructor
};
class Circle : public Shape {
public:
std::unique_ptr<Shape> clone() const override;
std::unique_ptr<Shape> create() const override;
// ...
};
std::unique_ptr<Shape> Circle::clone() const { return new Circle(*this); }
std::unique_ptr<Shape> Circle::create() const { return new Circle(); }У класса Фигура есть метод clone, который позволяет скопировать текущий объект в новый объект. Метод create позволяет дефолтно создать объект того же класса.
В класса Circle эти методы переопределяются. Теперь можно не зная точного типа полиморфного объекта вызвать его конструктор по умолчанию и копирования.
std::unique_ptr<Shape> ptr = std::make_unique<Circle>();
auto new_obj = ptr->create();
auto copy_obj = ptr->copy();
В эти методы также можно добавить аргументов, в том числе и полиморфных типов. Главное, чтобы сигнатуры методов в наследниках и базе совпадали.
Можете кстати порассуждать в комментах, как бы выглядели виртуальные конструкторы и код, который бы их использовал.
Use well-known tools for your task. Stay cool.
#interview #cppcore #pattern