Вопросы по С++ (часть 1)

Первая часть моих ответов на вопросы из списка.

1) Как определить, что связный список является кольцевым?

Запомнить указатель (итератор) на первый элемент списка. Начать обход списка от первого элемента к последнему. Если в процессе обхода текущий указатель равен указателю на первый элемент списка, то список кольцевой. Если список пройден - список не является кольцевым.

2) Какой целочисленный тип использовать?

Это определяется прикладной задачей, решаемой в рамках данной предметной области. Во-первых, нужно определиться с шириной коридора принимаемых значений переменной целочисленного типа (char, short, int, long, long long; с использованием модификаторов signed, unsigned). Во-вторых, учесть количество памяти, отводимое под переменную соответствующего типа (1, 2, 4 или 8 байт).

3) Каково отличие между конструктором и деструктором.

Конструктор - специальный метод объекта, вызываемый сразу после выделения ему памяти, выполняющий инициализацию членов объекта. Деструктор - метод вызываемый перед освобождением памяти, отводимой объекту, служащий для “деинициализации” (например, удаления) членов объекта.

4) В чём разница между агрегированием и ассоциированием?

Под агрегированием понимается владение (создание) объектом A объекта B. При этом допускается, что жизненный цикл объекта B не зависит от A.

Под ассоциированием понимается использование объектом A объекта B: объект A содержит ссылку или указатель на объект B и использует объект B, когда это необходимо.

5) Как определить размер класса?

Использовать конструкцию sizeof (имя класса) или sizeof (объект).

6) Как реализовать функцию itoa?

Вместо слов:

void itoa(int value, char *str)
{
    char *ptr = str;
    bool sign = value < 0;

    if (sign)
        value = -value;
    
    while (value)
    {
        char digit = value % 10;
        *ptr++ = '0' + digit;
        value /= 10;
    }

    if (sign)
        *ptr++ = '-';

    *ptr-- = '\0';

    while (str < ptr)
    {
        char symbol = *str;
        *str++ = *ptr;
        *ptr-- = symbol;
    }
}

7) Как определить указатель на функцию?

typedef void (*fn)(int, char *);

8) Как связать программу, написанную на C++, с функциями, написанными на C?

Объявление функций, написанных на C, нужно обернуть конструкцией вида extern "C" { }.

9) Как вернуть структуру из функции?

Обыкновенно, по значению (структура разместится в стеке).

10) Как написать функцию, которая инвертирует связный список?

Вариант 1. Перестановка значений. Двигаясь одновременно справа и слева к центру (до момента когда указатели встретятся) переставлять элементы. Минус - для этого нужно получить указатель на последний элемент (то есть обойти список).

Вариант 2. Перестановка указателей. Двигаясь в прямом направлении (слева направо): а) запоминаем указатель на текущий элемент и указатель на следующий элемент, б) у текущего элемента указателю на следующий элемент присваиваем значение указателя на предыдущий элемент, в) указателю на предыдущий элемент присваиваем адрес текущего элемента, г) переходим к следующему элементу по известному указателю (до тех пор пока он не NULL).

11) Какие преимущества от использования исключений C++?

С помощью исключений могут быть зафиксированы случаи некорректной работы программы (возникновение ошибок), приняты спасательные меры и сохранена работоспособность программы. Является альтернативой возврата кода ошибки. Имеет преимущество: исключение может быть поймано на любом уровне иерархии вызовов.

12) Какая разница между структурой и классом в C++?

Почти никакой. В структуре по умолчанию все члены являются публичными. В классе - приватными.

13) Какие есть модификаторы элементов классов/структур и переменных?

auto - обычный модификатор; является модификатором по умолчанию для локальных переменных функции.

register - модификатор, указывающий, что локальная переменная должна размещаться в регистре процессора, а не в памяти (стеке).

static - переменная существует на протяжении жизненного цикла программы (глобальная + ограничение области видимости).

extern - указание на глобальную переменную, которая где-то инициализирована и доступна всем частям программы.

mutable - только для членов класса; разрешает модификацию члена класса, даже если он объявлен в коде как константный.

14) Что такое встроенные (inline) функции?

Функции, которые не оформлены как самостоятельная единица. Тело таких функций копируется в то место программы, из которого осуществляется её “вызов”. Использование inline-функций даёт выигрыш в скорости исполнения (не происходит сохранение и восстановление слова-состояния процессора в стеке), но увеличивает размер программы.

15) На что указывает ключевое слово extern в объявлении функции?

На то, что функция определена в другом файле.

16) -

17) Для чего используют ключевое слово static в объявлении функции?

Ключевым словом static ограничивается область видимости функции (её нельзя вызвать из другого файла). Если функция-член класса объявлена статической, то она может модифицировать только статичные члены класса.

18) Что такое неявное преобразование типов в конструкторе?

C++ допускает неявное преобразование аргумента Arg, указанного в конструкторе MyClass(int Arg) в объект MyClass. Для запрещения такого преобразования для конструктора необходимо указать ключевое слово explicit.

19) Что такое конструктор копирования?

Конструктор, который принимает единственный аргумент точно такого же типа как и сам объект. Предполагается, что создаваемый объект будет копией объекта, на который ссылается аргумент.

20) Что такое пространство имён (namespace)?

Средство разделения имён символов (функций, классов, переменных), служащее для исключения коллизий.

21) Что такое абстрактная функция?

Функция, которая должна быть обязательно определена в производном классе. Невозможно создать экземпляр базового класса, в котором объявлена абстрактная функция.

22) Что такое оператор разрешения контекста?

:: позволяет указать контекст класса, переменной, функции.

23) Что такое абстракция?

Средство для использования объектов без знания деталей реализации.

24) В чём разница между #define и const.

#define является директивой препроцессора, которая служит для подстановки в код определённых с её помощью величин. Модификатор const позволяет один раз определить константную переменную и использовать её в тех местах программы, где это необходимо (по сравнению с #define это иногда сокращает размер программы).

25) В чём разница между перегрузкой и переопределением метода?

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

Переопределение позволяет изменить поведение виртуальной функции у производного класса.

c++, вопросы, программирование