⚙️ C++
Aqui está a tradução do artigo de teoria de programação do russo para o português, seguindo todas as regras fornecidas.
ООП в C++: классы, наследование и полиморфизм с примерами
C++ — один из первых языков, сделавших ООП популярным. В отличие от Java, в C++ ООП — это выбор, а не обязательство: можно писать и процедурно. Но ООП даёт мощные инструменты для организации сложного кода.
Класс и объект: аналогия с животными
#include <iostream>
#include <string>
using namespace std;
class Dog {
public: // Публичный раздел: доступен всем
string name;
string breed;
int age;
// Методы
void bark() {
cout << name << " (" << breed << "): ГАВ-ГАВ!" << endl;
}
void eat(string food) {
cout << name << " ест " << food << endl;
}
void describe() {
cout << name << ", " << breed << ", " << age << " лет" << endl;
}
}; // Точка с запятой обязательна!
int main() {
// Создание объектов (переменных типа Dog)
Dog rex;
rex.name = "Рекс";
rex.breed = "Немецкая овчарка";
rex.age = 3;
Dog sharik;
sharik.name = "Шарик";
sharik.breed = "Дворняжка";
sharik.age = 7;
// Каждый объект независим!
rex.bark();
sharik.bark();
rex.describe();
sharik.describe();
return 0;
}
Конструктор и деструктор
#include <iostream>
#include <string>
using namespace std;
class Person {
private: // Приватный раздел: доступен только внутри класса
string name;
int age;
public:
// Конструктор: вызывается при создании объекта
// Список инициализации — более эффективный способ
Person(string name, int age) : name(name), age(age) {
cout << "Создан: " << name << endl;
}
// Конструктор по умолчанию
Person() : name("Неизвестно"), age(0) {
cout << "Создан пустой Person" << endl;
}
// Конструктор копирования
Person(const Person& other) : name(other.name + " (копия)"), age(other.age) {
cout << "Скопирован: " << name << endl;
}
// Деструктор: вызывается при удалении объекта
~Person() {
cout << "Удалён: " << name << endl;
}
// Геттеры
string getName() const { return name; } // const: метод не изменяет объект
int getAge() const { return age; }
// Сеттер с валидацией
void setAge(int newAge) {
if (newAge >= 0 && newAge <= 150) age = newAge;
else cout << "Ошибка: некорректный возраст" << endl;
}
void introduce() const {
cout << "Привет! Я " << name << ", мне " << age << " лет." << endl;
}
};
int main() {
Person ivan("Иван", 25); // Конструктор с параметрами
Person empty; // Конструктор по умолчанию
Person copy = ivan; // Конструктор копирования
ivan.introduce();
copy.introduce();
ivan.setAge(26);
ivan.setAge(200); // Ошибка: некорректный возраст
// Деструктор вызовется автоматически при выходе из области видимости
cout << "Конец main:" << endl;
// Здесь вызываются деструкторы в обратном порядке создания
return 0;
}
Инкапсуляция: public, private, protected
#include <iostream>
using namespace std;
class BankAccount {
private: // Доступно только внутри класса
string owner;
double balance;
string pin;
int failedAttempts;
protected: // Доступно в классе и наследниках
bool isBlocked;
public: // Доступно везде
BankAccount(string owner, double balance, string pin)
: owner(owner), balance(max(0.0, balance)),
pin(pin), failedAttempts(0), isBlocked(false) {}
// Геттеры (const — не изменяют объект)
string getOwner() const { return owner; }
double getBalance() const { return balance; }
bool getBlocked() const { return isBlocked; }
// Пополнение
void deposit(double amount) {
if (isBlocked) { cout << "Счёт заблокирован!" << endl; return; }
if (amount <= 0) { cout << "Сумма должна быть > 0" << endl; return; }
balance += amount;
cout << "Пополнение +" << amount << "₽. Баланс: " << balance << "₽" << endl;
}
// Снятие с PIN
bool withdraw(double amount, string enteredPin) {
if (isBlocked) { cout << "Счёт заблокирован!" << endl; return false; }
if (enteredPin != pin) {
if (++failedAttempts >= 3) { isBlocked=true; cout << "ЗАБЛОКИРОВАН!" << endl; }
else cout << "Неверный PIN. Попытка " << failedAttempts << "/3" << endl;
return false;
}
if (amount > balance) { cout << "Недостаточно средств" << endl; return false; }
balance -= amount; failedAttempts=0;
cout << "Снято -" << amount << "₽. Остаток: " << balance << "₽" << endl;
return true;
}
};
int main() {
BankAccount acc("Иван", 50000, "1234");
acc.deposit(15000);
acc.withdraw(5000, "9999"); // Неверный PIN
acc.withdraw(5000, "1234"); // Правильный
// acc.balance = 1e9; // ОШИБКА: balance is private
return 0;
}
Наследование
#include <iostream>
#include <string>
using namespace std;
// Базовый класс
class Animal {
protected:
string name;
int age;
public:
Animal(string name, int age) : name(name), age(age) {}
void breathe() { cout << name << " дышит" << endl; }
void eat(string food) { cout << name << " ест " << food << endl; }
virtual string sound() { return "..."; } // virtual — можно переопределить
void makeSound() {
cout << name << " говорит: " << sound() << endl;
}
string info() const {
return name + " (" + to_string(age) + " лет)";
}
};
// Dog наследует Animal
class Dog : public Animal {
string breed;
public:
Dog(string name, int age, string breed) : Animal(name, age), breed(breed) {}
void bark() { cout << name << " (" << breed << "): ГАВ!" << endl; }
string sound() override { return "ГАВ-ГАВ!"; } // override — переопределяем
string info() const {
return Animal::info() + ", порода: " + breed;
}
};
// Cat наследует Animal
class Cat : public Animal {
bool indoor;
public:
Cat(string name, int age, bool indoor) : Animal(name, age), indoor(indoor) {}
void purr() { cout << name << " мурлычет ♪" << endl; }
string sound() override { return "МЯУ~"; }
string info() const {
return Animal::info() + string(indoor ? ", домашняя" : ", уличная");
}
};
int main() {
Dog rex("Рекс", 3, "Овчарка");
Cat mur("Мурка", 5, true);
// Унаследованные методы
rex.breathe(); rex.eat("мясо");
mur.breathe();
// Специфичные методы
rex.bark();
mur.purr();
// Переопределённые
rex.makeSound(); // Рекс говорит: ГАВ-ГАВ!
mur.makeSound(); // Мурка говорит: МЯУ~
cout << rex.info() << endl;
cout << mur.info() << endl;
return 0;
}
Виртуальные функции и полиморфизм
#include <iostream>
#include <cmath>
#include <vector>
#include <memory> // unique_ptr
using namespace std;
class Shape {
protected:
string color;
public:
Shape(string c) : color(c) {}
virtual ~Shape() {} // Виртуальный деструктор — ОБЯЗАТЕЛЕН при наследовании!
virtual double area() const = 0; // = 0: чисто виртуальная функция
virtual double perimeter() const = 0; // Класс становится абстрактным
void describe() const {
cout << "[" << color << "] площадь=" << area()
<< ", периметр=" << perimeter() << endl;
}
};
class Circle : public Shape {
double r;
public:
Circle(string c, double r) : Shape(c), r(r) {}
double area() const override { return M_PI*r*r; }
double perimeter() const override { return 2*M_PI*r; }
};
class Rectangle : public Shape {
double w, h;
public:
Rectangle(string c, double w, double h) : Shape(c), w(w), h(h) {}
double area() const override { return w*h; }
double perimeter() const override { return 2*(w+h); }
};
int main() {
// Shape s("red"); // ОШИБКА: абстрактный класс!
// Полиморфизм через указатели/ссылки
vector<unique_ptr<Shape>> shapes;
shapes.push_back(make_unique<Circle>("красный", 5));
shapes.push_back(make_unique<Rectangle>("синий", 4, 6));
shapes.push_back(make_unique<Circle>("жёлтый", 2));
double totalArea = 0;
for (const auto& s : shapes) {
s->describe(); // Полиморфный вызов!
totalArea += s->area();
}
cout << "Общая площадь: " << totalArea << endl;
return 0;
}
Итого: что мы узнали
- ✅ Класс: шаблон с полями (данными) и методами (поведением)
- ✅
public: доступно всем;private: только внутри;protected: внутри + наследники - ✅ Конструктор: инициализирует объект; деструктор (
~): освобождает ресурсы - ✅ Список инициализации
: field(value)— эффективнее чем присваивание в теле - ✅ Наследование (
class Dog : public Animal): подкласс получает всё от родителя - ✅
virtual: функцию можно переопределить в подклассе - ✅
override: явно указываем что переопределяем родительский метод - ✅
= 0: чисто виртуальная функция → класс становится абстрактным - ✅ Виртуальный деструктор обязателен при наследовании!
- ✅
unique_ptr— умный указатель для безопасного управления памятью