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

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

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

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

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

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;

}

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

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

Share →

4 Responses to Задачка по программированию

  1. Anon says:

    В Вашем решение много ошибок, начиная от отсутствия проверки на присваивание себе, заканчивая небезопасностью относительно исключений. Вероятно, от Вас ожидали увидеть реализацию идиомы copy-and-swap.

    • bober_maniac says:

      Я правильно понимаю, что правильного в вашем понимании решения я не увижу?

      • Anon says:

        Я бы написал что-то такое.


        class Boo: public SuperBoo
        {
        private:
        Foo *fFoo1, *fFoo2;

        public:
        Boo(const Boo &rhs)
        : fFoo1(), fFoo2()
        {
        try {
        fFoo1 = new Foo(*rhs.fFoo1);
        fFoo2 = new Foo(*rhs.fFoo2);
        } catch (...) {
        delete fFoo1;
        delete fFoo2;
        throw;
        }
        }

        friend void swap(Boo &lhs, Boo &rhs) noexcept {
        using std::swap;

        swap(static_cast(lhs), static_cast(rhs));
        swap(lhs.fFoo1, rhs.fFoo1);
        swap(lhs.fFoo2, rhs.fFoo2);
        }

        Boo &operator=(Boo rhs) {
        swap(*this, rhs);
        return *this;
        }
        };

        • Маздайщик says:

          swap(static_cast(lhs), static_cast(rhs));
          Сначала думал, что за странный синтаксис, потом понял, что разметка порезала угловые скобки около static_cast. В угловых скобках, должно быть, имелся ввиду SuperBoo&.

          Кстати, copy-and-swap тут не гарантирует безопасности исключений, если не гарантируется безопасность swap для родительского класса.

Leave a Reply

Войти с помощью: 

Your email address will not be published. Required fields are marked *

PageLines