From the monthly archives: "December 2013"

Давным-давно, когда я искал работу, мне прислали одну интересную задачку, которую я до сих пор гуглю на просторах интернета. Причем гуглю безответно — народ ломает голову, но ничего толкового придумать не может.

Я не самый большой специалист по С++, поэтому тешу себя мыслью, что если я ошибаюсь — меня поправят, а если нет — пусть статья выходит в топы гугла и висит там, дабы ее прекратили давать на собеседованиях. Потому что задача идиотская.

Звучит она так:

Перегрузка оператора присваивания

Пусть есть класс

class Boo : public SuperBoo

{

Foo* fFoo1;

Foo* fFoo2;

}

Где Foo – мономорфный класс, а класс Boo владеет указателями fFoo1, fFoo2.

Задача: перегрузить оператор присваивания для класса Boo.

Начнем с первого — с мономорфного класса. Все знают, что ООП состоит из полиморфизма, инкапсуляции и наследования. Определение полиморфизма можно прочитать в википедии, а пользуясь нехитрой логикой можно понять, что мономорфный — антоним понятия «полиморфный». Таким образом, в нашем случае, мономорфный класс — это класс, указатель на который всегда представляет его самого, а не его наследника.

То есть мы можем гарантировать то, что за Foo* скрывается класс Foo, а не какой-нибудь class MegaFoo : public Foo.

Второй вывод, который мы можем сделать из текста задачи — что класс Boo владеет указателями, а значит удаляет их в деструкторе. Таким образом, нам необходимо помнить о политике владения при написании оператора присваивания и четко удалять и создавать новые объекты.

Третий вывод позволяет нам сделать наличие суперкласса у Foo. Вполне возможно, что у SuperFoo есть оператор присвания, а значит нам необходимо его вызвать. Если же его нет — не беда, всегда есть оператор присваивания по умолчанию, просто копирующий блок памяти.

Таким образом, по нашему трезвому измышлению, необходимо сделать следующее для успешного написания оператора присванивания:

  1. Вспомнить синтаксис оператора присваивания
  2. Удалить fFoo1 и fFoo2
  3. Вызвать родительский оператор присваивания
  4. Сделать копии fFoo1 и fFoo2 у правой части оператора
  5. Вернуть ссылку на себя

В коде это будет выглядеть следующим образом:

Boo& operator=(const Boo& other)
{

delete this->fFoo1;

this->fFoo1 = nullptr;

delete this->fFoo2;

this->fFoo2 = nullptr;

SuperBoo::operator=(other);

if(other.fFoo1)

this->fFoo1 = new Foo(*other.fFoo1);

if(other.fFoo2)

this->fFoo2 = new Foo(*other.fFoo2);

return *this;

}

Это я и выслал в ответ на «тестовое задание», на что мне было сказано, что с заданием я не справился.

До сих пор гадаю, где же ошибка? На ум, конечно, приходит консистентность данных, защита от сбоев при выделении памяти и прочие кошерные вещи, но тут уже мой разум пасует — не настолько хорошо я знаю С++.

Случайно от подруги узнал, что наша музыка ныне доступна для покупки в iTunes. Видимо, барабанщик барыжит. В общем, все как у взрослых — с обложкой и возможностью предварительного прослушивания. Кому понравится — налетай, торопись, покупай живопись.

PageLines