CCCPaste

Исключения и пространство имен 2

Хорошо! Ниже представлены 10 задач с решениями на тему **"Исключения"** и 10 задач с решениями на тему **"Пространство имён"**, каждая из которых иллюстрирует практическое применение этих концепций в C++.

---

## **Часть 1: Исключения**

---

### **Задача 1: Обработка неправильного формата даты**

**Описание:** Напишите программу, которая принимает строку в формате "DD/MM/YYYY" и проверяет, является ли она корректной датой (например, 30/02/2023 — некорректно). Если формат неверен или дата невозможна, выбросите исключение.

**Решение:**

```cpp
#include <iostream>
#include <string>
#include <stdexcept>
#include <sstream>

void validateDate(const std::string& dateStr) {
if (dateStr.size() != 10 || dateStr[2] != '/' || dateStr[5] != '/') {
throw std::invalid_argument("Неверный формат даты. Используйте DD/MM/YYYY.");
}

int day, month, year;
char sep1, sep2;
std::istringstream iss(dateStr);
iss >> day >> sep1 >> month >> sep2 >> year;

if (iss.fail() || day < 1 || day > 31 || month < 1 || month > 12) {
throw std::invalid_argument("Некорректные значения дня или месяца.");
}

// Простая проверка: февраль не может иметь 30 дней
if (month == 2 && day > 29) {
throw std::invalid_argument("Февраль не может иметь более 29 дней.");
}
std::cout << "Дата корректна: " << dateStr << std::endl;
}

int main() {
std::string input;
std::cout << "Введите дату в формате DD/MM/YYYY: ";
std::getline(std::cin, input);

try {
validateDate(input);
} catch (const std::invalid_argument& e) {
std::cerr << "Ошибка: " << e.what() << std::endl;
}
return 0;
}
```

---

### **Задача 2: Проверка корректности email**

**Описание:** Напишите функцию, которая проверяет, является ли строка корректным email адресом (должен содержать `@` и точку после `@`). Обработайте некорректный формат.

**Решение:**

```cpp
#include <iostream>
#include <string>
#include <stdexcept>

void validateEmail(const std::string& email) {
size_t atPos = email.find('@');
if (atPos == std::string::npos) {
throw std::invalid_argument("Email не содержит символ '@'.");
}
if (email.find('.', atPos) == std::string::npos) {
throw std::invalid_argument("Email не содержит доменное имя (точка после '@').");
}
std::cout << "Email корректен: " << email << std::endl;
}

int main() {
std::string email;
std::cout << "Введите email: ";
std::getline(std::cin, email);

try {
validateEmail(email);
} catch (const std::invalid_argument& e) {
std::cerr << "Ошибка: " << e.what() << std::endl;
}
return 0;
}
```

---

### **Задача 3: Обработка ошибки при чтении числа из строки**

**Описание:** Напишите программу, которая читает строку и пытается извлечь из неё **два** числа, разделённых пробелом. Обработайте случаи, когда строка не содержит чисел или содержит лишние символы.

**Решение:**

```cpp
#include <iostream>
#include <string>
#include <sstream>
#include <stdexcept>

std::pair<int, int> parseTwoNumbers(const std::string& input) {
std::istringstream iss(input);
int a, b;
char extra;
if (!(iss >> a >> b) || iss >> extra) {
throw std::invalid_argument("Ожидается два целых числа, разделённых пробелом.");
}
return {a, b};
}

int main() {
std::string input;
std::cout << "Введите два числа через пробел: ";
std::getline(std::cin, input);

try {
auto [num1, num2] = parseTwoNumbers(input);
std::cout << "Числа: " << num1 << ", " << num2 << std::endl;
} catch (const std::invalid_argument& e) {
std::cerr << "Ошибка: " << e.what() << std::endl;
}
return 0;
}
```

---

### **Задача 4: Обработка ошибки при создании вектора с отрицательным размером**

**Описание:** Напишите функцию, создающую вектор заданного размера. Обработайте попытку создания вектора с отрицательным размером.

**Решение:**

```cpp
#include <iostream>
#include <vector>
#include <stdexcept>

std::vector<int> createVector(int size) {
if (size < 0) {
throw std::domain_error("Размер вектора не может быть отрицательным.");
}
return std::vector<int>(size);
}

int main() {
int size;
std::cout << "Введите размер вектора: ";
std::cin >> size;

try {
auto vec = createVector(size);
std::cout << "Вектор успешно создан размером " << vec.size() << std::endl;
} catch (const std::domain_error& e) {
std::cerr << "Ошибка: " << e.what() << std::endl;
}
return 0;
}
```

---

### **Задача 5: Исключение при работе с библиотекой (условно)**

**Описание:** Представьте, что вы работаете с условной "библиотекой" для работы с изображениями. Функция `loadImage` может выбросить исключение, если формат не поддерживается. Имитируйте это поведение.

**Решение:**

```cpp
#include <iostream>
#include <string>
#include <stdexcept>

void loadImage(const std::string& filename) {
std::string ext = filename.substr(filename.find_last_of(".") + 1);
if (ext != "jpg" && ext != "png") {
throw std::runtime_error("Формат изображения не поддерживается: " + ext);
}
std::cout << "Изображение '" << filename << "' загружено." << std::endl;
}

int main() {
std::string file;
std::cout << "Введите имя файла изображения (jpg/png): ";
std::getline(std::cin, file);

try {
loadImage(file);
} catch (const std::runtime_error& e) {
std::cerr << "Ошибка загрузки: " << e.what() << std::endl;
}
return 0;
}
```

---

### **Задача 6: Исключение при попытке доступа к защищённым данным**

**Описание:** Напишите класс `SecureData`, который имеет приватные данные. Доступ к ним возможен только при предоставлении правильного "ключа". Если ключ неверен, выбросьте исключение.

**Решение:**

```cpp
#include <iostream>
#include <stdexcept>
#include <string>

class SecureData {
std::string data = "Секретные данные";
std::string key = "12345";
public:
std::string getData(const std::string& inputKey) {
if (inputKey != key) {
throw std::runtime_error("Неверный ключ доступа.");
}
return data;
}
};

int main() {
SecureData sd;
std::string input;
std::cout << "Введите ключ: ";
std::getline(std::cin, input);

try {
std::cout << "Данные: " << sd.getData(input) << std::endl;
} catch (const std::runtime_error& e) {
std::cerr << "Ошибка: " << e.what() << std::endl;
}
return 0;
}
```

---

### **Задача 7: Обработка ошибки при конвертации валюты**

**Описание:** Напишите функцию `convertCurrency`, которая принимает сумму и код валюты. Если код валюты неизвестен, выбросьте исключение.

**Решение:**

```cpp
#include <iostream>
#include <stdexcept>
#include <string>

double convertCurrency(double amount, const std::string& currency) {
if (currency == "USD") return amount * 1.0;
if (currency == "EUR") return amount * 0.85;
if (currency == "RUB") return amount * 90.0;
throw std::invalid_argument("Неизвестный код валюты: " + currency);
}

int main() {
double amount;
std::string currency;
std::cout << "Введите сумму: ";
std::cin >> amount;
std::cout << "Введите код валюты (USD, EUR, RUB): ";
std::cin >> currency;

try {
double result = convertCurrency(amount, currency);
std::cout << "Результат: " << result << " USD" << std::endl;
} catch (const std::invalid_argument& e) {
std::cerr << "Ошибка: " << e.what() << std::endl;
}
return 0;
}
```

---

### **Задача 8: Исключение при работе с базой данных (условно)**

**Описание:** Имитируйте подключение к базе данных. Если строка подключения некорректна (например, отсутствует хост), выбросьте исключение.

**Решение:**

```cpp
#include <iostream>
#include <string>
#include <stdexcept>

void connectToDatabase(const std::string& connStr) {
if (connStr.find("host=") == std::string::npos) {
throw std::runtime_error("Строка подключения не содержит 'host'.");
}
std::cout << "Подключение к базе данных установлено." << std::endl;
}

int main() {
std::string conn;
std::cout << "Введите строку подключения (например, host=localhost): ";
std::getline(std::cin, conn);

try {
connectToDatabase(conn);
} catch (const std::runtime_error& e) {
std::cerr << "Ошибка подключения: " << e.what() << std::endl;
}
return 0;
}
```

---

### **Задача 9: Обработка ошибки при вычислении факториала**

**Описание:** Напишите функцию `factorial`, которая вычисляет факториал числа. Обработайте отрицательные числа и числа, превышающие разумный предел (например, 20).

**Решение:**

```cpp
#include <iostream>
#include <stdexcept>

long long factorial(int n) {
if (n < 0) {
throw std::domain_error("Факториал отрицательного числа не определён.");
}
if (n > 20) {
throw std::overflow_error("Факториал числа слишком велик для вычисления.");
}
long long result = 1;
for (int i = 2; i <= n; ++i) {
result *= i;
}
return result;
}

int main() {
int num;
std::cout << "Введите число для вычисления факториала: ";
std::cin >> num;

try {
long long result = factorial(num);
std::cout << "Факториал " << num << " = " << result << std::endl;
} catch (const std::domain_error& e) {
std::cerr << "Ошибка: " << e.what() << std::endl;
} catch (const std::overflow_error& e) {
std::cerr << "Ошибка: " << e.what() << std::endl;
}
return 0;
}
```

---

### **Задача 10: Обработка исключения при логировании**

**Описание:** Напишите простую функцию логирования в файл. Если файл не удаётся открыть, выбросьте исключение.

**Решение:**

```cpp
#include <iostream>
#include <fstream>
#include <stdexcept>
#include <string>

void logToFile(const std::string& message, const std::string& filename) {
std::ofstream file(filename, std::ios::app);
if (!file.is_open()) {
throw std::runtime_error("Не удалось открыть файл для логирования: " + filename);
}
file << message << std::endl;
file.close();
std::cout << "Сообщение записано в лог." << std::endl;
}

int main() {
std::string msg, file;
std::cout << "Введите сообщение для лога: ";
std::getline(std::cin, msg);
std::cout << "Введите имя файла лога: ";
std::getline(std::cin, file);

try {
logToFile(msg, file);
} catch (const std::runtime_error& e) {
std::cerr << "Ошибка логирования: " << e.what() << std::endl;
}
return 0;
}
```

---

## **Часть 2: Пространство имён**

---

### **Задача 1: Организация функций ввода-вывода**

**Описание:** Создайте пространство имён `IO` с функциями `readInt()` и `writeInt()`, которые обертывают `std::cin` и `std::cout`.

**Решение:**

```cpp
#include <iostream>

namespace IO {
int readInt() {
int val;
std::cin >> val;
return val;
}

void writeInt(int val) {
std::cout << val << std::endl;
}
}

int main() {
std::cout << "Введите число: ";
int num = IO::readInt();
std::cout << "Вы ввели: ";
IO::writeInt(num);
return 0;
}
```

---

### **Задача 2: Пространство имён для констант физических величин**

**Описание:** Создайте пространство имён `Physics` с константами, такими как `SPEED_OF_LIGHT`, `GRAVITY`.

**Решение:**

```cpp
#include <iostream>

namespace Physics {
const double SPEED_OF_LIGHT = 299792458.0; // м/с
const double GRAVITY = 9.81; // м/с^2
}

int main() {
std::cout << "Скорость света: " << Physics::SPEED_OF_LIGHT << " м/с" << std::endl;
std::cout << "Ускорение свободного падения: " << Physics::GRAVITY << " м/с^2" << std::endl;
return 0;
}
```

---

### **Задача 3: Пространство имён для математических функций**

**Описание:** Создайте пространство имён `MathUtils` с функцией `power`, которая возводит число в степень.

**Решение:**

```cpp
#include <iostream>

namespace MathUtils {
double power(double base, int exp) {
double result = 1.0;
for (int i = 0; i < exp; ++i) {
result *= base;
}
return result;
}
}

int main() {
double base = 2.0;
int exp = 3;
std::cout << base << "^" << exp << " = " << MathUtils::power(base, exp) << std::endl;
return 0;
}
```

---

### **Задача 4: Использование `using` для сокращения кода**

**Описание:** В `main` используйте `using` для импорта конкретной функции из пространства `MathUtils` и вызовите её.

**Решение:**

```cpp
#include <iostream>

namespace MathUtils {
double power(double base, int exp) {
double result = 1.0;
for (int i = 0; i < exp; ++i) {
result *= base;
}
return result;
}
}

int main() {
using MathUtils::power;
std::cout << "2^4 = " << power(2, 4) << std::endl;
return 0;
}
```

---

### **Задача 5: Пространство имён для работы с геометрией**

**Описание:** Создайте пространство имён `Shapes` с классом `Rectangle`, который имеет метод `area`.

**Решение:**

```cpp
#include <iostream>

namespace Shapes {
class Rectangle {
double width, height;
public:
Rectangle(double w, double h) : width(w), height(h) {}
double area() const {
return width * height;
}
};
}

int main() {
Shapes::Rectangle rect(5.0, 3.0);
std::cout << "Площадь прямоугольника: " << rect.area() << std::endl;
return 0;
}
```

---

### **Задача 6: Вложенные пространства имён для библиотеки**

**Описание:** Создайте вложенное пространство имён `Graphics::2D` с функцией `drawLine`.

**Решение:**

```cpp
#include <iostream>

namespace Graphics {
namespace _2D {
void drawLine(int x1, int y1, int x2, int y2) {
std::cout << "Рисуем линию от (" << x1 << "," << y1 << ") до (" << x2 << "," << y2 << ")" << std::endl;
}
}
}

int main() {
Graphics::_2D::drawLine(0, 0, 10, 10);
return 0;
}
```

---

### **Задача 7: Повторное объявление пространства имён с классом и функцией**

**Описание:** Объявите пространство `Game` дважды: в первом — класс `Player`, во втором — функцию `resetGame`.

**Решение:**

```cpp
#include <iostream>

namespace Game {
class Player {
public:
std::string name;
Player(const std::string& n) : name(n) {}
};
}

namespace Game {
void resetGame() {
std::cout << "Игра сброшена." << std::endl;
}
}

int main() {
Game::Player p("Alice");
std::cout << "Игрок: " << p.name << std::endl;
Game::resetGame();
return 0;
}
```

---

### **Задача 8: Пространство имён для настроек приложения**

**Описание:** Создайте пространство имён `AppConfig` с переменными `windowWidth`, `windowHeight`.

**Решение:**

```cpp
#include <iostream>

namespace AppConfig {
int windowWidth = 800;
int windowHeight = 600;
}

int main() {
std::cout << "Размер окна: " << AppConfig::windowWidth << "x" << AppConfig::windowHeight << std::endl;
return 0;
}
```

---

### **Задача 9: Пространство имён для вспомогательных утилит**

**Описание:** Создайте пространство `Utils` с функцией `trim`, которая удаляет пробелы в начале и в конце строки.

**Решение:**

```cpp
#include <iostream>
#include <string>

namespace Utils {
std::string trim(const std::string& str) {
size_t start = str.find_first_not_of(" \t\n\r");
if (start == std::string::npos) return "";
size_t end = str.find_last_not_of(" \t\n\r");
return str.substr(start, end - start + 1);
}
}

int main() {
std::string input = " hello world ";
std::cout << "До: [" << input << "]" << std::endl;
std::cout << "После: [" << Utils::trim(input) << "]" << std::endl;
return 0;
}
```

---

### **Задача 10: Анонимное пространство имён для локальной утилиты**

**Описание:** Создайте анонимное пространство имён с функцией `isEven`, которая используется только внутри текущего файла.

**Решение:**

```cpp
#include <iostream>

namespace {
bool isEven(int n) {
return n % 2 == 0;
}
}

int main() {
int num = 42;
if (isEven(num)) {
std::cout << num << " - чётное." << std::endl;
} else {
std::cout << num << " - нечётное." << std::endl;
}
return 0;
}
```

---

Эти задачи показывают, как исключения и пространства имён применяются на практике для повышения надёжности, читаемости и структурированности кода.