Тест на знання C++

Квітень 28th, 2009

Життя підкинуло цікаву ідею для перевірки практичних навичок C++ програміста. Таке собі тестове завдання.

Нижче наведено клас — зв’язаний список, призначений для зберігання всяких різних об’єктів. Клас поганий, нормальний С++ програміст такого собі дозволяти не повинен. Як ви гадаєте, що саме недобре у цьому класі?

  1. class Linked_Lists
  2. {
  3.     public:
  4.         Linked_Lists();
  5.         ~Linked_Lists();
  6.         bool add(void *data);
  7.         bool remove_head();
  8.         bool first();
  9.         bool last();
  10.         bool next();
  11.         bool prev();
  12.         void* get_data();
  13.         bool is_empty();
  14.         int get_count();
  15.  
  16.     protected:
  17.         struct Node
  18.         {
  19.             void *data;
  20.             Node *prev_node;
  21.             Node *next_node;
  22.         };
  23.         Node *head;
  24.         Node *tail;
  25.         Node *current;
  26.         int count;
  27. };

Слід сказати, тут дещо специфічний дизайн, так уже сталося. Елементи додаються та видаляються зі списку за принципом FIFO. Водночас, доступний вказівник, який можна туди-сюди пересувати по списку, щоб отримати доступ до будь-яких даних. Втім, це не суттєво. Припустимо, так було потрібно для чогось.

Справжній недолік цього класу в іншому. У якості підказки варто глянемо на реалізацію деструктора:

  1. Linked_Lists::~Linked_Lists()
  2. {
  3.     Node *node;
  4.  
  5.     if (head == 0) return;
  6.  
  7.     first();
  8.     do
  9.     {
  10.         node = current;
  11.         next();
  12.         delete node->data;
  13.         delete node;
  14.     } while (current != 0);
  15. }

Що ж саме у ньому не так? (ще…)

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

Булевий тип у чистому C

Лютий 25th, 2009

В принципі, це й так всі нормальні люди знають, але хай буде у якості нотаток на випадок раптового удару граблями приступу склерозу
Так от, відомо, що у C булівський тип відсутній. Можна використовувати такого шось типу

  1. #ifndef __cplusplus
  2.  
  3. #ifndef bool
  4. typedef char bool;
  5. #endif
  6.  
  7. #ifndef true
  8. #define true    ((bool) 1)
  9. #endif
  10.  
  11. #ifndef false
  12. #define false   ((bool) 0)
  13. #endif
  14.  
  15. #endif   /* not C++ */

Але всі велосипеди було вже давно винайдено й стандартизовано. Слово українській вікіпедії:

stdbool.h — заголовний файл стандартної бібліотеки мови програмування С, котрий містить чотири макроси для роботи з типом даних bool. Даний заголовний файл з’явився у стандартні C99.

Визначення макросів згідно стандарту IEEE Std 1003.1-2001:

  • bool котрий розширюється до _Bool
  • true котрий розширюється до 1
  • false котрий розширюється до 0
  • __bool_true_false_are_defined котрий розширюється до 1

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

Функція повідомлення про помилку

Січень 14th, 2009

У QT знайшов черговий приклад, як не треба робити. Спішу поділитися :)

Уявіть собі, є якийсь там клас QPluginLoader, який має метод QString QPluginLoader::errorString (). Типу, якщо шось там спрацювало не так як треба, то цей метод повертатиме текстовий опис помилки. Питання на засипку: що видає ця функція, якщо все пройшло добре? Коли б це проектували нормальні люди, то відповідь була б “No error”, або щось подібне. Стандартна perror(), наприклад, в такому випадку чітко і ясно пише “Success” (в англійській локалі, звісно). Натомість витвір заморожених норвежців запросто видає “Unknown error”. А фіглі його тут зайвий раз викликають…

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

Стандарти C та C++

Січень 12th, 2009

Вирішив викласти у себе, може, комусь знадобиться

стандарт C (C99)
чинний на сьогоднішній день стандарт C++

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

Рефакторінг

Листопад 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++ | Теґи:, , , | Кометарів немає

Багатозначне слово Static

Вересень 30th, 2008

C++ відомий своєю заплутаністю. Ключових слів ніби й небагато, але кожне може бути використане у багатьх контекстах. В цьому дописі я спробую звести воєдино всі відомі мені способи використання слова static. Хто знає, може буде щось таке, чого ви не знали раніше :) (ще…)

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

Еліпсис, або як створити свій аналог printf

Вересень 13th, 2008

Еліпсисом (англ ellipsis) називають елемент синтаксису мови C, що представляє собою три крапки. Наприклад, як у оголошенні фукнції printf :
int printf(const char *format, ...);

Еліпсис означає, що на цьому місці знаходится якась кількість змінних якогось типу. Функція сама має визначити, які саме змінні їй передали.

(ще…)

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

Відмінність між C та C++

Серпень 28th, 2008

Я до цього часу вважав, що C++ є розширенням C. Ну, насправді, я розумію, що це абсолютно різні мови, з різними сферами застосування і т.д. і блаблабла… Але от була така впевненість, що формально нема в C нічого такого, чого б не було C++. Тобто, я вважав, що сертифікований компілятор C++ має без будь-яких зауважень скомпілювати C-програму. А от ні, виявляється, є одна штука, якою ці мови відрізняються. Хоча, звісно, це така, дуже теоретична відмінність, наврядчи хтось може з цим зіткнутися в реальному житті.
(ще…)

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

Опції gcc, про які варто знати

Липень 16th, 2008

Використання консольного GCC – страшний нічний кошмар для новачків, що звикли до зручних графічних середовищ програмування у Windows. Величезна кількість опцій командного рядка лякає навіть відчайдухів, які відкривають man в надії знайти рішення проблеми. В цій замітці я коротко опишу найцікавіші опції GCC, про які варто знати усім. (ще…)

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