Добавь Успадкування (наследование) и Шаблоны методов и классов
В этт код:
#include <iostream>
#include <fstream>
#include <exception>
#include <vector>
#include <string>
#include <cassert>

class FileException : public std::exception
{
    virtual const char *what() const throw()
    {
        return "Помилка читання з файлу!";
    }
} file_exception;

class Player
{
public:
    std::string name;
    int number;
    int points;
    int age;

    // Конструктор с аргументами
    Player(std::string n, int num, int p, int a) : name(n), number(num), points(p), age(a) {}

    // добавлено const
    void display() const
    {
        std::cout << name << ", Гравець #" << number << ", Бали: " << points << ", Вік: " << age << std::endl;
    }
};

class Team
{
public:
    std::string name;
    std::vector<Player> players;

    Team() {} //  конструктор по умолчанию
    Team(std::string n) : name(n) {}

    void add_player(Player player)
    {
        players.push_back(player);
    }

    void display_players() const
    {
        std::cout << "Гравці за " << name << ":" << std::endl;
        for (const auto &player : players)
        {
            player.display();
        }
    }
};

class League
{
public:
    std::string name;
    std::vector<Team> teams;

    League() {} //  конструктор по умолчанию
    League(std::string n) : name(n) {}

    void add_team(Team team)
    {
        teams.push_back(team);
    }

    void display_teams() const
    {
        std::cout << "Команди ліги " << name << ":" << std::endl;
        for (const auto &team : teams)
        {
            std::cout << team.name << std::endl;
        }
    }
};

class Championship
{
public:
    std::string name;
    std::vector<League> leagues;

    Championship() {} //  конструктор по умолчанию
    Championship(std::string n) : name(n) {}

    void add_league(League league)
    {
        leagues.push_back(league);
    }

    void display_leagues() const
    {
        std::cout << "Ліги чемпіонату " << name << ":" << std::endl;
        for (const auto &league : leagues)
        {
            std::cout << league.name << std::endl;
        }
    }
};

void test()
{
    // Створено дві команди
    Team team1("DINAZ");
    Team team2("Chicago Bulls");

    // Додайте гравців до команди1
    team1.add_player(Player("Василь", 1, 20, 25));
    team1.add_player(Player("Петро", 2, 15, 24));
    team1.add_player(Player("Іван", 3, 30, 28));

    // Додайте гравців до команди2
    team2.add_player(Player("Олег", 4, 10, 27));
    team2.add_player(Player("Михайло", 5, 25, 26));
    team2.add_player(Player("Тарас", 6, 18, 24));

    // Створено лігу
    League league1;
    league1.name = "Ліга 1";

    // Додайте команди до ліги
    league1.add_team(team1);
    league1.add_team(team2);

    // Створено другу лігу
    Team team3("LA Lakers");
    Team team4("Golden State Warriors");

    // Додайте гравців до команди3
    team3.add_player(Player("Леброн", 1, 30, 36));
    team3.add_player(Player("Ентоні", 2, 25, 28));
    team3.add_player(Player("Девіс", 3, 20, 28));

    // Додайте гравців до команди4
    team4.add_player(Player("Каррі", 4, 35, 33));
    team4.add_player(Player("Томпсон", 5, 20, 31));
    team4.add_player(Player("Грін", 6, 15, 31));

    League league2;
    league2.name = "Ліга 2";

    // Додайте команди до другої ліги
    league2.add_team(team3);
    league2.add_team(team4);

    // Створено чемпіонат
    Championship championship("Чемпіонат 2023");

    // Додайте ліги до чемпіонату
    championship.add_league(league1);
    championship.add_league(league2);

    // Збереження тесту в файл
    std::ofstream outfile(team1.name + ".bin", std::ios::binary);
    outfile.write(reinterpret_cast<char*>(&team1), sizeof(Team));
    outfile.close();

    // Тестове читання з файлу
    Team team_read;
    std::ifstream infile(team1.name + ".bin", std::ios::binary);
    infile.read(reinterpret_cast<char*>(&team_read), sizeof(Team));
    infile.close();

    // Переконайтеся, що прочитаний об'єкт збігається з оригіналом
    assert(team1.name == team_read.name);
    assert(team1.players.size() == team_read.players.size());
    for (int i = 0; i < team1.players.size(); i++)
    {
        assert(team1.players[i].number == team_read.players[i].number);
        assert(team1.players[i].points == team_read.players[i].points);
        assert(team1.players[i].age == team_read.players[i].age);
    }

    // Протестуйте відображення команд для кожної ліги
    std::cout << "Оберіть лігу:" << std::endl;
    for (int i = 0; i < championship.leagues.size(); i++)
    {
        std::cout << i + 1 << ". " << championship.leagues[i].name << std::endl;
    }
    int league_choice;
    std::cin >> league_choice;

    if (league_choice >= 1 && league_choice <= championship.leagues.size())
    {
        const auto& league = championship.leagues[league_choice - 1];
        league.display_teams();

        std::cout << "Оберіть команду:" << std::endl;
        for (int i = 0; i < league.teams.size(); i++)
        {
            std::cout << i + 1 << ". " << league.teams[i].name << std::endl;
        }
        int team_choice;
        std::cin >> team_choice;

        if (team_choice >= 1 && team_choice <= league.teams.size())
        {
            const auto& team = league.teams[team_choice - 1];
            team.display_players();

            std::cout << "Оберіть гравця:" << std::endl;
            for (int i = 0; i < team.players.size(); i++)
            {
                std::cout << i + 1 << ". Гравець #" << team.players[i].number << std::endl;
            }
            int player_choice;
            std::cin >> player_choice;

            if (player_choice >= 1 && player_choice <= team.players.size())
            {
                const auto& player = team.players[player_choice - 1];
                std::cout << "Гравець #" << player.number << " має " << player.points << " очок і йому " << player.age << " років." << std::endl;
            }
            else
            {
                std::cout << "Неправильний вибір." << std::endl;
            }
        }
        else
        {
            std::cout << "Неправильний вибір." << std::endl;
        }
    }
    else
    {
        std::cout << "Неправильний вибір." << std::endl;
    }
}

int main()
{
    try
    {
        test();
    }
    catch(std::exception& e)
    {
        std::cout << e.what() << std::endl;
    }

    return 0;
}