Elementor Header #8

36. Побочные эффекты

1. Введение

В программировании побочные эффекты — это изменения состояния системы, которые происходят в результате выполнения функций или методов, и которые могут повлиять на поведение программы за пределами этой функции. Понимание и управление побочными эффектами являются важными для написания надёжного и предсказуемого кода. В этом уроке мы рассмотрим, что такое побочные эффекты, как их избегать и управлять ими в C++.

2. Что такое побочные эффекты?

Побочные эффекты возникают, когда функция или метод изменяет состояние системы или объектов, помимо возврата значения. Это может включать изменение глобальных переменных, модификацию объектов, передачу данных по ссылке и другие изменения.

Пример побочного эффекта:

				
					#include <iostream>
int globalVar = 0;

void incrementGlobalVar(){
    globalVar++;
}

int main(){
    incrementGlobalVar();
    std::cout << "Global variable after increment: " << globalVar << std::endl; // Выводит: Global variable after increment: 1
    return 0;
}

				
			

В этом примере функция incrementGlobalVar изменяет глобальную переменную globalVar, что является побочным эффектом.

3. Примеры побочных эффектов

Изменение глобальных переменных:

				
					#include <iostream>
int globalValue = 10;

void modifyGlobalValue(){
    globalValue = 20;
}

int main(){
    modifyGlobalValue();
    std::cout << "Global value: " << globalValue << std::endl; // Выводит: Global value: 20
    return 0;
}

				
			

В этом примере функция modifyGlobalValue изменяет значение глобальной переменной globalValue.

Изменение переданных по ссылке параметров:

				
					#include <iostream>

void doubleValue(int& value) {
    value *= 2;
}

int main(){
    int num = 5;
    doubleValue(num);
    std::cout << "Doubled value: " << num << std::endl; // Выводит: Doubled value: 10 
    return 0;
}

				
			

Функция doubleValue изменяет значение переменной num, переданной по ссылке, что является побочным эффектом.

Взаимодействие с внешними ресурсами:

				
					#include <iostream>
#include <fstream>

void writeFile(const std::string& filename, const std::string& content) {
    std::ofstream file(filename);
    if (file.is_open()) {
        file << content;
    }
}

int main(){
    writeFile("example.txt", "Hello, World!");
    return 0;
}

				
			

Функция writeFile изменяет содержимое файла, что также является побочным эффектом.

4. Управление побочными эффектами

Для управления побочными эффектами важно следовать лучшим практикам программирования:

Минимизируйте побочные эффекты: Пытайтесь проектировать функции так, чтобы они имели минимальные побочные эффекты. Функции без побочных эффектов называются чистыми функциями.

Пример чистой функции:

				
					int add(int a, int b){
    return a + b;
}

				
			

Функция add является чистой, так как она не изменяет состояние и всегда возвращает одинаковый результат для одних и тех же входных данных.

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

				
					void printMessage(const std::string& message){
    std::cout << message << std::endl;
}

				
			

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

Используйте методы класса и избегайте изменения состояния объекта: Если в классе есть методы, которые изменяют состояние объекта, следует явно документировать это.

				
					class Counter {
    public:
        void increment(){
            ++count;
        }
    
        int getValue() const{
            return count;
        }

    private:
        int count = 0;
};

				
			

В этом примере метод increment изменяет состояние объекта Counter, а метод getValue не изменяет состояние и является константным.

Заключение

Побочные эффекты могут усложнить отладку и тестирование программ, так как они могут изменять состояние системы или объектов за пределами функций. Чтобы избежать неожиданных последствий и сделать код более предсказуемым, важно управлять побочными эффектами и стремиться к написанию чистых функций.

5. Тестовое задание

Напишите класс BankAccount, который моделирует банковский счёт. Класс должен содержать следующие методы:

  1. deposit(double amount) — добавляет сумму на счёт.
  2. withdraw(double amount) — снимает сумму со счёта (если на счёте достаточно средств).
  3. getBalance() — возвращает текущий баланс счёта.
  4. Убедитесь, что методы класса работают правильно и не имеют побочных эффектов за пределами класса.

Примерный код:

				
					#include <iostream>

class BankAccount {
    public:
        BankAccount(double initialBalance) : balance(initialBalance) {}
    
        void deposit(double amount){
            if (amount > 0) {
                balance += amount;
            }
        }
    
        void withdraw(double amount){
            if (amount > 0 && amount <= balance) {
                balance -= amount;
            }
        }
    
        double getBalance() const{
            return balance;
        }
    
    private:
        double balance;
};

int main(){
    BankAccount account(100.0);

    account.deposit(50.0);
    account.withdraw(30.0);

    std::cout << "Current balance: " << account.getBalance() << std::endl; // Выводит: Current balance: 120.0
    return 0;
}

				
			

Этот пример показывает, как можно управлять состоянием объекта класса BankAccount и избегать побочных эффектов, обеспечивая корректное поведение методов.

logo