Рефакторінг

Листопад 10th, 2008

Ще одне цікаве завдання, з тих, що пропонує Яндекс:

Есть класс CodeGenerator, который умеет генерить код на разных языках.

  1.  
  2. class CodeGenerator
  3. {
  4. public:
  5.     enum Lang {JAVA, C_PLUS_PLUS, PHP};
  6.     CodeGenerator(Lang language) { _language=language; }
  7.     std::string generateCode()
  8.     {
  9.         switch(_language) {
  10.         case JAVA:        //return generated java code
  11.         case C_PLUS_PLUS: //return generated C++ code
  12.         case PHP:         //return generated PHP code
  13.         }
  14.         throw new std::logic_error("Bad language");
  15.     }
  16.     std::string someCodeRelatedThing() // used in generateCode()
  17.     {
  18.         switch(_language) {
  19.         case JAVA:        //return generated java-related stuff
  20.         case C_PLUS_PLUS: //return generated C++-related stuff
  21.         case PHP:         //return generated PHP-related stuff
  22.         }
  23.         throw new std::logic_error("Bad language");
  24.     }
  25.  
  26. private:
  27.     Lang _language;
  28. }
  29.  

Исходя из предположения, что количество языков будет добавляться, предложите refactoring кода. Аргументируйте преимущество вашего кода над существующим.

(ще…)

Категорії: C/C++, Паттерни проектування | Теґи:, , , , , , | Кометарів немає

На роботу в Яндекс

Листопад 7th, 2008

Виявляється, Яндекс постійно набирає нових людей, зокрема, розробників C++. Перша частина співбесіди — онлайн. Завдання, що там пропонуються, без сумніву, варті уваги. Ось , наприклад, таке

  1.  
  2. class Top {
  3.   public:
  4.     virtual ~Top (){}
  5. };
  6.  
  7. class Right : virtual public Top {
  8.   public:
  9.     void f () {}
  10. };
  11.  
  12. class Left : virtual public Top {
  13.   public:
  14.     void f () {}
  15. };
  16.  
  17. class Bottom : public Right, public Left {
  18.   public:
  19. /*
  20. * что надо написать чтобы выполнялось требование описанное в main
  21. */
  22. };
  23.  
  24. int main (int, char**) {
  25.   Bottom b;
  26.   b.f(); // Требование: вызов Left::f()
  27. }
  28.  

Split post hereЗвісно, перше, що спадає на думку, зробити шось типу

void f () { Left::f();}

Але так негарно. Виклик однієї функції через іншу… Не дуже добре, особливо якщо в реальному житті трапиться метод з багатьма параметрами.

Насправді, розумні люди підказали , треба робити так:


using Left::f;

Цей запис виглядав би так само, навіть якби у батьківських класах метод f приймав би якісь параметри.

В тому коді є ще пара цікавих моменти, про які особисто я не знав, не знав, та й забув.

По-перше, спосіб наслідування virtual publiс. Виявляється, слово virtual в даному випадку означає, що у класі Bottom буде присутня одна і тільки одна реалізація об’єкту класу Top. Якби virtual не було, тоді виникала б неоднозначність при використанні членів класу Top, успадкованих як в Left, так і в Right. Втім, в прикладі цього не видно, бо в Top занадто спрощений.

По-друге, клас Top має віртуальний деструктор. Питання: який взагалі сенс деструктору бути віртуальним, коли його все одно не можна перекрити в класі-нащадку? Погугливши, знайшов відповідь . Справа в тому, що якби не слово virtual, то ось в такому випадку

int main {
Top* tp = new Right;
}

було б викликано деструктор явно заданого класу (Top), в той час, коли насправді треба викликати ~Right.

Категорії: C/C++ | Теґи:, , , | Кометарів немає