
- Главная
- Каталог
- Интернет технологии
- C/C++ | Вопросы собесов
C/C++ | Вопросы собесов
Разбираем вопросы с собеседований на С/С++ разработчика
Статистика канала
Square нарушает LSP, потому что он изменяет поведение методов setWidth и setHeight, что может привести к неожиданным результатам при использовании объекта Square как Rectangle.
class Rectangle {
protected:
int width, height;
public:
virtual void setWidth(int w) { width = w; }
virtual void setHeight(int h) { height = h; }
int getWidth() const { return width; }
int getHeight() const { return height; }
int area() const { return width * height; }
};
class Square : public Rectangle {
public:
void setWidth(int w) override {
width = w;
height = w; // Изменяем и ширину, и высоту
}
void setHeight(int h) override {
height = h;
width = h; // Изменяем и высоту, и ширину
}
};{}
🟠Соблюдение LSP
Лучше всего избегать такого наследования, которое приводит к нарушению LSP. В этом случае можно использовать другой подход, например, композицию вместо наследования. Теперь Rectangle и Square наследуют от абстрактного класса Shape, и каждый класс реализует метод area согласно своей логике, не нарушая LSP.
class Shape {
public:
virtual int area() const = 0;
virtual ~Shape() = default;
};
class Rectangle : public Shape {
protected:
int width, height;
public:
Rectangle(int w, int h) : width(w), height(h) {}
void setWidth(int w) { width = w; }
void setHeight(int h) { height = h; }
int getWidth() const { return width; }
int getHeight() const { return height; }
int area() const override { return width * height; }
};
class Square : public Shape {
int side;
public:
Square(int s) : side(s) {}
void setSide(int s) { side = s; }
int getSide() const { return side; }
int area() const override { return side * side; }
};{}
Ставь 👍 и забирай 📚 Базу знаний
#include <iostream>
#include <unistd.h>
int main() {
pid_t pid = fork(); // Создание нового процесса
if (pid == 0) {
// Дочерний процесс
std::cout << "Это дочерний процесс" << std::endl;
} else {
// Родительский процесс
std::cout << "Это родительский процесс, PID дочернего процесса: " << pid << std::endl;
}
return 0;
}{}
🚩Потоки
Это наименьшая единица выполнения в рамках процесса. Потоки одного процесса разделяют одно адресное пространство и ресурсы, такие как память и дескрипторы файлов.
🟠Разделение ресурсов
Потоки разделяют память и ресурсы процесса, что делает межпоточное взаимодействие более эффективным.
🟠Создание
Создание потоков обычно быстрее и менее ресурсозатратно по сравнению с процессами.
🟠Параллелизм
Потоки позволяют выполнять несколько частей программы параллельно, что улучшает производительность на многоядерных системах.
#include <iostream>
#include <thread>
void printMessage(const std::string& message) {
std::cout << message << std::endl;
}
int main() {
std::thread t1(printMessage, "Привет из потока 1");
std::thread t2(printMessage, "Привет из потока 2");
t1.join(); // Ожидание завершения потока
t2.join();
return 0;
}{}
Ставь 👍 и забирай 📚 Базу знаний_fastcall передает первые два целочисленных аргумента (например, int, char, long) через регистры ECX и EDX на архитектуре x86. Остальные аргументы передаются через стек.
🟠Обратная совместимость
_fastcall обеспечивает совместимость с другими соглашениями о вызове, но это может потребовать дополнительных усилий для обеспечения совместимости при смешивании разных соглашений о вызове в одном проекте.
🟠Оптимизация производительности
Передача аргументов через регистры уменьшает накладные расходы, связанные с использованием стека, что может улучшить производительность в функциях, которые вызываются часто или требуют высокой производительности.
#include <iostream>
// Функция, использующая соглашение о вызове _fastcall
int __fastcall add(int a, int b) {
return a + b;
}
int main() {
int result = add(5, 3);
std::cout << "Result: " << result << std::endl; // Вывод: Result: 8
return 0;
}{}
🚩Примечания и ограничения
🟠Платформенная зависимость
_fastcall специфичен для архитектуры x86 и поддерживается не всеми компиляторами. На x64 используется другое соглашение о вызове, и _fastcall не применим.
🟠Совместимость с другими соглашениями о вызове
Если вы используете _fastcall вместе с другими соглашениями о вызове (например, __cdecl, __stdcall), нужно быть осторожным, чтобы избежать ошибок при вызове функций с разными соглашениями о вызове.
🟠Использование в современных проектах
В современных проектах использование _fastcall редко необходимо, так как современные компиляторы достаточно умны, чтобы автоматически оптимизировать вызовы функций, используя подходящие соглашения о вызове. В большинстве случаев вручную указывать _fastcall нет необходимости.
#include <iostream>
// Проверка платформы
#ifdef _M_IX86 // Если используется компилятор для архитектуры x86
int __fastcall add(int a, int b) {
return a + b;
}
#else
int add(int a, int b) {
return a + b;
}
#endif
int main() {
int result = add(5, 3);
std::cout << "Result: " << result << std::endl; // Вывод: Result: 8
return 0;
}{}
Ставь 👍 и забирай 📚 Базу знанийstd::back_inserter — это адаптер итератора из библиотеки STL, который позволяет удобно добавлять элементы в конец контейнера при использовании алгоритмов стандартной библиотеки (например, std::copy, std::transform и т. д.).
Он создает итератор-вставку (inserter iterator), который при попытке записи нового элемента фактически вызывает метод push_back() у контейнера.
🚩Почему он нужен?
Обычно алгоритмы STL работают с итераторами и требуют, чтобы целевой контейнер уже содержал достаточно места для копирования или вставки элементов. back_inserter позволяет избежать этого ограничения, автоматически расширяя контейнер по мере необходимости.
🚩Пример использования
Без back_inserter (приведет к ошибке!)
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> source = {1, 2, 3, 4, 5};
std::vector<int> destination; // Пустой контейнер
// Ошибка! У destination нет места для элементов
std::copy(source.begin(), source.end(), destination.begin());
return 0;
}{}
Используем back_inserter (правильный вариант)
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main() {
std::vector<int> source = {1, 2, 3, 4, 5};
std::vector<int> destination; // Начинаем с пустого контейнера
// Используем back_inserter
std::copy(source.begin(), source.end(), std::back_inserter(destination));
// Вывод результата
for (int num : destination) {
std::cout << num << " ";
}
return 0;
}{}
Вывод
1 2 3 4 5{}
🚩Где используется `back_inserter`?
🟠**std::transform – Преобразование элементов**
Применяем функцию ко всем элементам и добавляем результат в новый контейнер
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main() {
std::vector<int> nums = {1, 2, 3, 4, 5};
std::vector<int> squared;
std::transform(nums.begin(), nums.end(), std::back_inserter(squared),
[](int x) { return x * x; });
for (int num : squared) {
std::cout << num << " ";
}
return 0;
}{}
Вывод:
1 4 9 16 25{}
std::unique_copy – Удаление дубликатов
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main() {
std::vector<int> nums = {1, 2, 2, 3, 4, 4, 5};
std::vector<int> unique_nums;
std::unique_copy(nums.begin(), nums.end(), std::back_inserter(unique_nums));
for (int num : unique_nums) {
std::cout << num << " ";
}
return 0;
}{}
Вывод:
1 2 3 4 5{}
Ставь 👍 и забирай 📚 Базу знанийdeque является частью стандартной библиотеки шаблонов (STL) и объявляется в заголовочном файле <deque>.
🚩Основные характеристики:
🟠Быстрый доступ к элементам:
deque обеспечивает доступ к элементам по индексу с амортизированной временной сложностью O(1).
🟠Двусторонняя очередь:
Позволяет эффективно добавлять и удалять элементы как с начала, так и с конца очереди.
🟠Динамический размер:
deque автоматически изменяет свой размер по мере добавления или удаления элементов, подобно vector.
🟠Не требует смежного хранения:
В отличие от vector, элементы deque могут быть размещены в различных сегментах памяти, что делает его более гибким для частых операций вставки и удаления.
🚩Основные операции:
🟠Добавление элементов:
push_back(), push_front()
🟠Удаление элементов:
pop_back(), pop_front()
🟠Доступ к элементам:
operator[], at(), front(), back()
🟠Размер и емкость:
size(), empty(), resize()
🟠Итераторы:
Поддержка итераторов для прохода по элементам
#include <iostream>
#include <deque>
int main() {
std::deque<int> dq;
// Добавление элементов в конец
dq.push_back(1);
dq.push_back(2);
dq.push_back(3);
// Добавление элементов в начало
dq.push_front(0);
std::cout << "Deque elements: ";
for (int elem : dq) {
std::cout << elem << " ";
}
std::cout << std::endl;
// Удаление элемента с конца
dq.pop_back();
// Удаление элемента с начала
dq.pop_front();
std::cout << "Deque elements after pop operations: ";
for (int elem : dq) {
std::cout << elem << " ";
}
std::cout << std::endl;
return 0;
}{}
Ставь 👍 и забирай 📚 Базу знанийОтзывы канала
- Добавлен: Сначала новые
- Добавлен: Сначала старые
- Оценка: По убыванию
- Оценка: По возрастанию
Каталог Телеграм-каналов для нативных размещений
C/C++ | Вопросы собесов — это Telegam канал в категории «Интернет технологии», который предлагает эффективные форматы для размещения рекламных постов в Телеграмме. Количество подписчиков канала в 4.3K и качественный контент помогают брендам привлекать внимание аудитории и увеличивать охват. Рейтинг канала составляет 5.2, количество отзывов – 1, со средней оценкой 5.0.
Вы можете запустить рекламную кампанию через сервис Telega.in, выбрав удобный формат размещения. Платформа обеспечивает прозрачные условия сотрудничества и предоставляет детальную аналитику. Стоимость размещения составляет 3636.36 ₽, а за 3 выполненных заявок канал зарекомендовал себя как надежный партнер для рекламы в TG. Размещайте интеграции уже сегодня и привлекайте новых клиентов вместе с Telega.in!
Вы снова сможете добавить каналы в корзину из каталога
Комментарий