Как сгенерировать pure virtual function call исключение?
Нужно вызвать чисто виртуальный метод в конструкторе родительского класса, то есть до создания дочернего, в котором этот метод реализован. Так как современный компилятор не даст это сделать напрямую, то нужно будет использовать промежуточный метод.
Нужно вызвать чисто виртуальный метод в конструкторе родительского класса, то есть до создания дочернего, в котором этот метод реализован. Так как современный компилятор не даст это сделать напрямую, то нужно будет использовать промежуточный метод.
Когда следует использовать виртуальное наследование?
Хотя идеально вообще избегать виртуального наследования (вы должны знать, как будет использоваться ваш класс), все же важно иметь четкое представление о том, как работает виртуальное наследование:
Итак, когда у вас есть класс (класс A), который наследуется от двух родителей (B и C), оба из которых имеют общего родителя (класс D), как показано на картинке. Если вы не используете виртуальное наследование в этом случае, вы получите две копии D в классе A: одну из B и одну из C. Чтобы это исправить, вам нужно изменить объявления классов C и B на виртуальные:
class C: virtual public D {
};
class B: virtual public D {
};
Хотя идеально вообще избегать виртуального наследования (вы должны знать, как будет использоваться ваш класс), все же важно иметь четкое представление о том, как работает виртуальное наследование:
Итак, когда у вас есть класс (класс A), который наследуется от двух родителей (B и C), оба из которых имеют общего родителя (класс D), как показано на картинке. Если вы не используете виртуальное наследование в этом случае, вы получите две копии D в классе A: одну из B и одну из C. Чтобы это исправить, вам нужно изменить объявления классов C и B на виртуальные:
class C: virtual public D {
};
class B: virtual public D {
};
Что быстрее: постфиксные инкрементные операторы или префиксные? Чем отличается их сигнатура?
Префиксные операторы быстрее. В постфиксных операторах производится дополнительная операция сохранения предыдущего состояния объекта, а затем только увеличение на 1, а в префиксном операторе после инкрементирования объекта, сразу возвращается ссылка объект.
Сигнатура их отличается фиктивным параметром int у постфиксного оператора.
Префиксные операторы быстрее. В постфиксных операторах производится дополнительная операция сохранения предыдущего состояния объекта, а затем только увеличение на 1, а в префиксном операторе после инкрементирования объекта, сразу возвращается ссылка объект.
Сигнатура их отличается фиктивным параметром int у постфиксного оператора.
Что такое хеш-функция? Объясните на примере
Хеш-функция — это функция, которая принимает на вход некоторые данные и возвращает фиксированный размер выходных данных, называемый хешем. Такие функции широко используются в C++ для решения задач с поиском и индексированием данных. Они позволяют быстро находить элементы в массивах или хранилищах данных.
Рассмотрим применение на примере кода выше:
Мы создаем объект хеш-функции для строки и используем его для вычисления хеша для строки "Hello, world!". Результатом выполнения программы будет вывод на экран хеш-значения для этой строки.
Хеш-функция — это функция, которая принимает на вход некоторые данные и возвращает фиксированный размер выходных данных, называемый хешем. Такие функции широко используются в C++ для решения задач с поиском и индексированием данных. Они позволяют быстро находить элементы в массивах или хранилищах данных.
Рассмотрим применение на примере кода выше:
Мы создаем объект хеш-функции для строки и используем его для вычисления хеша для строки "Hello, world!". Результатом выполнения программы будет вывод на экран хеш-значения для этой строки.
Что такое void указатель? Можно ли разыменовать указатель void, не зная его типа?
void указатель — это указатель, который можно использовать для указания на любые данные любого произвольного типа. Указатель void может быть разыменован только после явного приведения. Например:
int a = 5;
void *b = &a;
printf(“%d\n”, *((int*)b));
void указатель — это указатель, который можно использовать для указания на любые данные любого произвольного типа. Указатель void может быть разыменован только после явного приведения. Например:
int a = 5;
void *b = &a;
printf(“%d\n”, *((int*)b));
Что такое виртуальный деструктор и зачем он используется в C++?
В C++ виртуальный деструктор используется для правильного освобождения памяти при удалении объекта через указатель на базовый класс. Если базовый класс имеет виртуальный деструктор, то при удалении объекта через указатель на базовый класс будет вызван деструктор не только базового класса, но и всех его производных классов. Это позволяет избежать утечек памяти и неопределенного поведения при работе с полиморфными объектами.
Если виртуального деструктора не объявлено в базовом классе, то при удалении производного объекта через указатель на базовый класс будут вызваны только деструкторы базового класса, что может привести к утечкам памяти и неопределенному поведению.
В C++ виртуальный деструктор используется для правильного освобождения памяти при удалении объекта через указатель на базовый класс. Если базовый класс имеет виртуальный деструктор, то при удалении объекта через указатель на базовый класс будет вызван деструктор не только базового класса, но и всех его производных классов. Это позволяет избежать утечек памяти и неопределенного поведения при работе с полиморфными объектами.
Если виртуального деструктора не объявлено в базовом классе, то при удалении производного объекта через указатель на базовый класс будут вызваны только деструкторы базового класса, что может привести к утечкам памяти и неопределенному поведению.
Бывает такое, что оператор new не выделяет память?
Ответ:
Да, бывает, когда new передаётся указатель на уже выделенную память (например, с помощью malloc). Это называется placement new. И оператор new без изменения возвращает второй параметр - указатель (void* operator new(std::size_t, void*)). Это используется для создания объектов в выделенном "хранилище" или после malloc.
Важно! В этом случае деструктор нужно вызывать самостоятельно!
Ответ:
Важно! В этом случае деструктор нужно вызывать самостоятельно!
Что делает алгоритм move?
Синтаксис:
std::move(first, last, result);
Перемещает элементы диапазона [first,last) в диапазон, начиная с позиции result.
Значение элементов в [first,last) массиве передается элементам, на которые указывает result. После вызова элементы в диапазоне [first,last) остаются в неопределенном, но допустимом состоянии.
Синтаксис:
std::move(first, last, result);
Перемещает элементы диапазона [first,last) в диапазон, начиная с позиции result.
Значение элементов в [first,last) массиве передается элементам, на которые указывает result. После вызова элементы в диапазоне [first,last) остаются в неопределенном, но допустимом состоянии.
Что такое класс хранения?
Класс, который определяет срок существования, компоновку и расположение переменных/функций в памяти.
В C++ поддерживаются такие классы хранения: auto, static, register, extern и mutable.
Обратите внимание, что register устарел для C++11. Для C++17 он был удален и зарезервирован для будущего использования.
Класс, который определяет срок существования, компоновку и расположение переменных/функций в памяти.
В C++ поддерживаются такие классы хранения: auto, static, register, extern и mutable.
Обратите внимание, что register устарел для C++11. Для C++17 он был удален и зарезервирован для будущего использования.
Объясните ключевые слова mutable и volatile.
Ключевое слово volatile сообщает компилятору, что переменная может измениться без ведома компилятора. Переменные, объявленные как volatile, не будут кэшироваться компилятором и, таким образом, всегда будут считываться из памяти.
Ключевое слово mutable можно использовать для переменных-членов класса. Изменяемые переменные могут меняться из константных функций-членов класса.
Ключевое слово volatile сообщает компилятору, что переменная может измениться без ведома компилятора. Переменные, объявленные как volatile, не будут кэшироваться компилятором и, таким образом, всегда будут считываться из памяти.
Ключевое слово mutable можно использовать для переменных-членов класса. Изменяемые переменные могут меняться из константных функций-членов класса.
Для чего используется ключевое слово explicit?
Ключевое слово explicit используется для того, чтобы пометить конструкторы, которые не должны неявно преобразовывать типы. Оно является необязательным для конструкторов, которые принимают ровно один аргумент, и работает на конструкторах (с одним аргументом), так как только эти конструкторы могут использоваться при приведении типов.
Ключевое слово explicit используется для того, чтобы пометить конструкторы, которые не должны неявно преобразовывать типы. Оно является необязательным для конструкторов, которые принимают ровно один аргумент, и работает на конструкторах (с одним аргументом), так как только эти конструкторы могут использоваться при приведении типов.
Перечислите все способы синхронизации процессов.
1. Использование мьютексов (std::mutex). Мьютекс позволяет захватывать его одним потоком, блокируя доступ другим потокам.
2. Использование семафоров (std::semaphore). Семафоры позволяют ограничивать количество потоков, которые могут одновременно захватить семафор.
3. Использование условных переменных (std::condition_variable). Они позволяют блокировать поток до наступления некоторого события.
4. Использование флагов и барьеров (std::atomic_flag, std::barrier).
5. Передача сообщений между потоками через очереди (std::queue).
6. Использование фьючерсов и промисов (std::promise, std::future).
Выбор конкретного механизма зависит от сценария использования и требований к синхронизации. Главное при этом избегать длительных и взаимных блокировок.
1. Использование мьютексов (std::mutex). Мьютекс позволяет захватывать его одним потоком, блокируя доступ другим потокам.
2. Использование семафоров (std::semaphore). Семафоры позволяют ограничивать количество потоков, которые могут одновременно захватить семафор.
3. Использование условных переменных (std::condition_variable). Они позволяют блокировать поток до наступления некоторого события.
4. Использование флагов и барьеров (std::atomic_flag, std::barrier).
5. Передача сообщений между потоками через очереди (std::queue).
6. Использование фьючерсов и промисов (std::promise, std::future).
Выбор конкретного механизма зависит от сценария использования и требований к синхронизации. Главное при этом избегать длительных и взаимных блокировок.
Какой код выполняется до функции main?
Ответ:
Конструкторы глобальных объектов.
Ответ: