Или третий пост о том, какие знания и навыки помогли мне пройти собеседование в Order Capital. Предыдущие посты:
— Собеседование в Order Capital. Часть 1
— Собеседование в Order Capital. Часть 2
Третье собеседование было с моим текущим руководителем, которого в компании считают самым большим знатоком С++ 💪. Мне дали 3 задачи, про каждую из которых можно рассказать отдельную историю. Я так сделаю: сейчас расскажу, что помогло справиться с первой, а про две другие — в следующих постах.
Первая задача была на динамический полиморфизм в C++. Были весьма стандартный для таких задач код и вопрос — что выведет код?
struct B {
~B() {
std::cout << "B::~B()" << std::endl;
}
};
struct D : B {
~D() {
std::cout << "D::~D()" << std::endl;
}
};
int main() {
std::sharead_ptr<B> p1 = std::make_shared<D>();
}Если знаете C++, напишите в комментариях, что бы вы ответили. А потом продолжайте чтение.
После внимательного чтения кода хочется ответить, что на экране появится только
B::~B(), потому что деструктор у B невиртуальный. И это ... неверно. Этот код корректно разрушит объект типа D и выведетD::~D()
B::~B()
Я именно так и ответил, и это было чистое везение 😉
Когда мы делали модуль про наследование в "Жёлтом поясе по С++", мы искали способы не рассказывать в нём про виртуальные методы, чтобы не перегрузить людей материалом. При этом очень хотелось показать людям, как сложить в один контейнер объекты разных типов, являющихся наследниками одного базового класса. Тогда кто-то из преподавателей написал и запустил примерно такой код:
/* Определение структур B и D из кода выше*/
int main() {
std::vector<std::shared_ptr<B>> objects;
for (size_t i = 0; i < 5; ++i) {
objects.push_back(std::make_shared<D>());
}
}
Мы очень удивились, увидев, что деструктор
D вызывается, несмотря на то, что он невиртуальный, и стали разбираться, как же это работает. Оказалось, что std::shared_ptr хранит внутри себя deleter, который знает тип объекта, переданного в конструктор, и поэтому может вызвать правильный деструктор! Если в коде выше заменить shared_ptr на unique_ptr, то чуда уже не будет — будет вызываться только деструктор B, потому что в uniqure_ptr deleter является частью типа. В общем, моё везение в первой задаче состояло в том, что я уже столкнулся с ней в "Жёлтом поясе по С++" 😎
🤔 Интересно, как бы стало развиваться собеседование, если я бы не знал этой особенности
shared_ptr? Наверное, мы углубились бы в его внутреннее устройство... В этой задаче был ещё миллион вопросов про виртуальные функции и «умные» указатели, но на них все несложно ответить, если хорошо
unique_ptr и shared_ptr.Итого, справиться с первой задачей мне помогли:
✅ удача — неотъемлемая спутница успеха
✅ хорошее знание динамического полиморфизма в C++
Расскажите, а как вам везло на собеседованиях?