Пятничная болталогия и никакой технички
Уберите упоминание курсов из своего резюме
Это одна из рекомендаций, которую я выдаю при ревью резюме: курсы по С++ должны быть убраны из резюме. Как и все остальные курсы, если они не являются всемирно признанными и не обладают уровнем сертификаций AWS, Microsoft, CCNP и им подобных. Я понимаю, что очень хочется добавить в список достижений очередной пояс непонятного цвета или ступень Professional, ведь менеджеры курсов утверждают, что это нужно "обязательно сделать", ведь это "выделит вас среди остальных кандидатов"...бла-бла-бла🥱 Увы, это старые шаблоны из старых методичек, которые писались задолго до того, как онлайн IT курсы полностью дискредитировали себя.
Когда-то онлайн курсы - это была попытка восполнить нехватку кадров в IT отрасли. Если копнуть глубоко в прошлое, то онлайн курсы изначально были бесплатными, организовывались крупными компаниями и на них брали практически всех желающих. С ростом зарплат и хайпа айтишки начало появляться все больше и больше онлайн школ. Для справки: в 2020 году было несколько десятков школ, сейчас - несколько сотен. Далее в ход включились эффективные менеджеры и продажники, которые начали завлекать в онлайн-школы всех: агрессивная реклама от каждого блогера, специальные условия на кредиты, обещания заоблачных денег и комфортных условий труда. Помню, что примерно в пик хайпа я воспользовался служебным положением и просмотрел анкеты со свежего потока студентов на курс Data Science: из 50 человек практически все были без вышки, больше половины - охранники, баристы, мастера маникюра. Я не хочу быть слишком токсичным (а в данном случае вариантов нет ☢️), но будем честны: вы изучали статистику? Как вы думаете, насколько реально её объяснить охраннику возраста 30+ и без вышки?
Это и привело к тому, что подавляющее большинство студентов закончили обучение в первые месяцы. И в этом полностью вина онлайн школ. Если бы не жажда наживы, то с большинством вкатунов должен был состояться диалог примерного содержания: "DS требует специфической подготовки, будем честны, вы ей не обладаете. Давайте рассмотрим курсы ручных тестировщиков, они стоят дешевле в несколько раз, найти работу с ними проще, да на старте зарплата меньше, но на дистанции можно стать лидом и получать ровно те же деньги." Ах, мечты-мечты. В итоге, эта часть несостоявшихся вкатунов окрестила все курсы и всех причастных к курсам "инфоцыганами". Вот и неси теперь свет в массы😁
Часть студентов все-таки дошла до конца курсов. Кто-то это смог сделать самостоятельно, но большей части "помогли" онлайн-школы. Онлайн-школы начали делать всё, чтобы "дотолкать" студента до конца курса (а иначе он возврат потребует и негативный отзыв напишет): убрали все дедлайны и сроки ("учись в своем темпе"), убрали все защиты проектных работ, менторов практически обязали "гладить студентов по головке" и "поменьше указывать на ошибки в коде". Обучение свелось к прокликиванию тестов на платформе, формальному выполнению работ и проектов. В итоге студент получал заветный сертификат, составлял резюме и бежал вкатываться в IT. Вакансии разрабов стали заваливаться предложениями от выпускников курсов. Кстати, пропагандировать широким массам накрутку опыта начали первыми онлайн школы: они рекомендовали вместо обучения указывать фриланс🙃 Первое время выпускников даже звали на собесы. Но после десятков собесов, где кандидат не мог ответить ни на один вопрос, многие компании, а вслед за ними и рекрутеры ввели негласное правило: резюме выпускников онлайн-школ отклонять автоматически. Да-да, один из тех самых "редфлагов в резюме"🚩
Что мы имеем сейчас. То, что вы пошли на онлайн курсы, закончили их и получили сертификат - это замечательно. Некоторые онлайн курсы - это по-прежнему буст знаний за короткий срок. Например, сейчас мне нужно углубить знания по CI/CD. Конечно же, я не буду читать книжки и статьи, а прослушаю онлайн-курс. Но не стоит указывать в резюме, что вы приобрели знания на онлайн-курсе. В текущих реалиях рынка это лишь снизит конверсию вашего резюме и принесет вам больше проблем, чем пользы.
ЕГЭ по инфе
Какой язык программирования по вашему удобнее в использование на егэ по информатике и почему?
Основы программирования на C++: Наследование и полиморфизм
Прежде чем читать мою статью - реши для себя, зачем ты это делаешь. Даже если ты просто нормальный человек, лишним не будет.
Если вы настоящий профессионал программирования, то зачем вы тут сидите и читайте статью на пикабу? Если вы ради интереса зашли почитать, то претензий ноль, но если вы просто захотели задушить нового пользователя Пикабу минусами, то немедленно покиньте статью, вам однозначно интересно не будет.
Здравствуйте, мои маленькие любители программирования!
Наследование в C++
Наследование — это механизм объектно-ориентированного программирования (ООП), который позволяет создавать иерархии классов, где класс-наследник (производный класс) наследует поля и методы базового класса , изменяя их область видимости. В C++ поддерживается публичное одиночное наследование , при котором производный класс может использовать публичные и защищённые члены базового класса.
Пример наследования
class A {
private:
int x;
public:
void Func1();
void Func2();
};
class B : public A {
private:
int y;
public:
void Func2(); // Переопределение функции
void Func3();
};
Основные моменты:
Класс B включает в себя подобъект класса A.
Методы и поля класса A доступны в B, за исключением приватных полей.
Приватное поле x из A хранится внутри объекта типа B, но недоступно напрямую.
Использование:
int main() {
B b;
b.Func1(); // Унаследовано от A
b.Func2(); // Переопределено в B
b.A::Func2(); // Версия из A
b.Func3(); // Определено в B
}
Приведение типов
Объект производного класса может быть приведён к типу базового класса . Это позволяет использовать объекты производного класса там, где ожидается объект базового класса.
void DoSomething(const A&);
int main() {
B b;
DoSomething(b); // OK
}
Жизненный цикл объектов
При создании объекта производного класса сначала вызывается конструктор базового класса, затем конструктор производного. Деструкторы вызываются в обратном порядке.
class InheritedLogger : public Logger {
public:
InheritedLogger() { std::cout << "InheritedLogger()\n"; }
~InheritedLogger() { std::cout << "~InheritedLogger()\n"; }
};
int main() {
InheritedLogger x;
}
Вывод программы:
Logger(): 1
InheritedLogger()
~InheritedLogger()
~Logger(): 1
Наследование vs Композиция
Наследование (is-a):
Класс-наследник является частным случаем базового класса.
Пример: Car является Vehicle.
Композиция (has-a):
Класс содержит объект другого класса как поле.
Пример: Car имеет Engine.
Пример композиции:
class C {
private:
A a; // Композиция
int y;
public:
void Func1() { a.Func1(); } // Обёртка
void Func2();
void Func3();
const A& GetA() const { return a; }
};
Полиморфизм
Полиморфизм позволяет переопределять поведение функций базового класса в производных классах. Для этого используются виртуальные функции .
Пример:
class Animal {
public:
virtual std::string Voice() const { return "Generic voice"; }
};
class Cat : public Animal {
public:
std::string Voice() const override { return "Meow!"; }
};
class Dog : public Animal {
public:
std::string Voice() const override { return "Woof!"; }
};
Виртуальные функции:
Позволяют выбирать реализацию во время выполнения (позднее связывание ).
Если функция объявлена как чисто виртуальная , класс становится абстрактным .
class Animal {
public:
virtual std::string Voice() const = 0; // Чисто виртуальная функция
};
Создать объект абстрактного класса нельзя.
Производные классы должны реализовать все чисто виртуальные функции.
Полиморфизм и контейнеры
Для хранения объектов разных типов в контейнере используются указатели. Однако важно учитывать управление памятью.
Пример использования указателей:
std::vector<Animal*> zoo;
zoo.push_back(new Cat("Tom"));
zoo.push_back(new Dog("Buffa"));
for (Animal* animal : zoo) {
Process(*animal); // Полиморфное поведение
delete animal; // Освобождение памяти
}
Важно:
Для корректного удаления объектов деструктор базового класса должен быть виртуальным .
class Animal {
public:
virtual ~Animal() {}
};
Умные указатели
Для безопасного управления памятью лучше использовать умные указатели , такие как std::unique_ptr или std::shared_ptr.
Пример с std::unique_ptr:
std::vector<std::unique_ptr<Animal>> zoo;
zoo.push_back(std::make_unique<Cat>("Tom"));
zoo.push_back(std::make_unique<Dog>("Buffa"));
for (const auto& animal : zoo) {
Process(*animal); // Полиморфное поведение
}
Умные указатели автоматически освобождают память при выходе из области видимости.
Итог
Наследование позволяет создавать иерархии классов и переиспользовать код.
Виртуальные функции обеспечивают полиморфное поведение.
Для работы с полиморфными объектами в контейнерах используйте указатели или умные указатели .
Абстрактные классы помогают определить общий интерфейс для производных классов.
Композиция предпочтительна, когда отношение между классами выражается через "имеет", а не "является".
Эти принципы являются основой объектно-ориентированного программирования в C++ и позволяют создавать гибкие, расширяемые и безопасные программы.
Основы программирования на C++: Жизненный цикл объекта
Прежде чем читать мою статью - реши для себя, зачем ты это делаешь. Даже если ты просто нормальный человек, лишним не будет.
Если вы настоящий профессионал программирования, то зачем вы тут сидите и читайте статью на пикабу? Если вы ради интереса зашли почитать, то претензий ноль, но если вы просто захотели задушить нового пользователя Пикабу минусами, то немедленно покиньте статью, вам однозначно интересно не будет.
Здравствуйте, мои маленькие любители программирования!
Жизненный цикл объекта в C++ управляется конструкторами, деструкторами и операторами присваивания. Рассмотрим ключевые аспекты на примере класса Logger, который логирует вызовы своих специальных функций.
Основные этапы жизненного цикла
Создание объекта:
Конструкторы: Вызываются при создании объекта. Могут быть параметризованными, копирующими или перемещающими.
Автоматические объекты (на стеке): Уничтожаются автоматически при выходе из области видимости.
Динамические объекты (в куче): Создаются через new, уничтожаются вручную через delete.
Пример:
Logger x1; // Вызов конструктора без аргументов
Logger* x2 = new Logger(1); // Динамический объект
delete x2; // Вызов деструктора
Копирование и присваивание:
Конструктор копирования: Создает новый объект как копию существующего.
Оператор присваивания: Модифицирует существующий объект.
По умолчанию компилятор генерирует тривиальные версии этих функций.
Пример:
Logger x3 = x1; // Конструктор копирования
x3 = x1; // Оператор присваивания
Перемещение:
Конструктор перемещения и оператор присваивания перемещением позволяют эффективно передавать ресурсы временных объектов.
Используются с std::move для явного указания перемещения.
Пример:
Logger x4 = std::move(x1); // Конструктор перемещения
x4 = Logger(); // Оператор присваивания перемещением
Деструктор: Вызывается при уничтожении объекта. Для автоматических объектов — при выходе из области видимости, для динамических — при вызове delete.
Особенности работы с классами
Статические поля: Общие для всех объектов класса. Используются для подсчета созданных экземпляров или хранения общих данных.
class Logger {
inline static int counter = 0; // Статическое поле
const int id;
public:
Logger() : id(++counter) {} // Инициализация id };
Композиция классов: При создании объекта сначала инициализируются его поля, затем тело конструктора. Деструкторы вызываются в обратном порядке.
class OuterLogger {
Logger inner1, inner2; // Поля инициализируются до тела конструктора
public: OuterLogger() { /* ... */ }
~OuterLogger() { /* ... */ } // Деструкторы inner2, inner1 вызываются после };
Временные объекты и контейнеры
Временные объекты существуют до конца выражения. Могут быть переданы в функции через rvalue-ссылки (&&), что позволяет избежать копирования.
void f(Logger&& x); // Перегрузка для временных объектов
f(Logger()); // Вызов версии с перемещением
Контейнеры (например, std::vector, std::list) управляют памятью автоматически. При реаллокации элементы могут копироваться или перемещаться.
std::vector<Logger> vec;
vec.emplace_back(); // Создание объекта напрямую в контейнере
vec.push_back(Logger()); // Создание временного объекта и его перемещение
Понимание жизненного цикла объектов помогает управлять ресурсами, избегать утечек и оптимизировать производительность.
1. Реализация класса Logger
Создайте класс Logger со следующими требованиями:
Имеет static int counter для подсчета созданных объектов.
Содержит const int id, инициализируемую в конструкторе через ++counter.
Реализуйте:
Конструктор по умолчанию (логирует "Constructor called, id=X").
Конструктор копирования (логирует "Copy constructor, id=X → Y").
Конструктор перемещения (логирует "Move constructor, id=X → Y").
Деструктор (логирует "Destructor, id=X").
Операторы присваивания (копирования и перемещения) с аналогичным логированием.
Цель: Научиться реализовывать все специальные функции класса.
2. Проверка порядка деструкторов
Создайте класс Composite, содержащий два поля типа Logger:
class Composite { Logger logger1; Logger logger2; public: Composite() { /* ... */ } };
В конструкторе Composite добавьте вывод "Composite constructor".
В деструкторе — "Composite destructor".
Создайте объект Composite в области видимости функции и определите порядок вызова деструкторов.
Цель: Понять порядок инициализации и уничтожения полей класса.
3. Временные объекты и перемещение
Напишите функцию:
void processLogger(Logger&& tempLogger) { std::cout << "Processing temporary logger" << std::endl; }
Создайте временный объект Logger() и передайте его в processLogger.
Объясните, почему не вызывается конструктор копирования.
Цель: Закрепить работу с rvalue-ссылками и перемещением.
4. Контейнеры и реаллокация
Создайте std::vector<Logger>.
Добавьте в него 3 элемента через push_back и emplace_back.
Запустите программу и объясните:
Почему при push_back(Logger()) вызывается перемещающий конструктор.
Как emplace_back позволяет избежать лишних вызовов конструкторов.
Что происходит при реаллокации вектора?
Цель: Изучить работу с контейнерами и оптимизацию через перемещение.
5. Динамические объекты и умные указатели
Создайте динамический объект Logger* dynamicLogger = new Logger();.
Удалите его через delete.
Перепишите код с использованием std::unique_ptr<Logger>.
Объясните, как умные указатели предотвращают утечки памяти.
Цель: Научиться управлять динамической памятью.
6. Запрет копирования
Модифицируйте класс Logger:
Удалите конструктор копирования и оператор присваивания.
Проверьте, что код Logger a; Logger b = a; вызывает ошибку компиляции.
Цель: Понять, как ограничивать жизненный цикл объектов.
7. Наследование и порядок вызовов
Создайте класс DerivedLogger : public Logger:
Добавьте поле Logger memberLogger.
В конструкторе и деструкторе DerivedLogger добавьте логирование.
Создайте объект DerivedLogger и зафиксируйте порядок вызовов конструкторов и деструкторов.
Цель: Изучить жизненный цикл объектов при наследовании.
8. Анализ кода
Дан код:
Logger createLogger() { return Logger(); } int main() { Logger a; Logger b = a; Logger c = std::move(createLogger()); std::vector<Logger> vec; vec.push_back(Logger()); return 0; }
Предскажите, сколько раз вызываются конструкторы (копирования, перемещения) и деструкторы.
Проверьте свой ответ, добавив логирование в класс Logger.
Цель: Научиться анализировать жизненный цикл объектов в реальном коде.


