C++: プロジェクト:住所録

最終更新:2026-08-31

レッスン50では、ユニットテストについて学びました。

ここでは、総合実践プロジェクト——住所録システムを作ります。

このプロジェクトはこれまで学んだ知識を統合します。


1. プロジェクト概要

(1) 1.1 機能一覧

機能 説明
追加 入力、名前、電話、メール
削除 名前で削除
変更 連絡先を変更
検索 名前で検索
一覧 全連絡先を表示
保存/読込 ファイルへ保存

(2) 1.2 クラス設計

TEXT 📖 参照専用
Contact(連絡先)
 - 名前、電話、メール

AddressBook(住所録)
 - vector<Contact> contacts
 - add, remove, update, find, display
 - save, load



2. Contactクラス

(1) 2.1 Contactクラスの定義

TEXT 📖 参照専用
#include <iostream>
#include <string>
#include <fstream>

class Contact {
private:
    std::string name;
    std::string phone;
    std::string email;

public:
    Contact() = default;
    Contact(const std::string& name, const std::string& phone, const std::string& email)
        : name(name), phone(phone), email(email) {}
    
    // Getter
    std::string getName() const { return name; }
    std::string getPhone() const { return phone; }
    std::string getEmail() const { return email; }
    
    // Setter
    void setName(const std::string& n) { name = n; }
    void setPhone(const std::string& p) { phone = p; }
    void setEmail(const std::string& e) { email = e; }
    
    // 表示
    void display() const {
        std::cout << "名前:" << name << std::endl;
        std::cout << "電話:" << phone << std::endl;
        std::cout << "メール:" << email << std::endl;
        std::cout << "-------------------" << std::endl;
    }
    
    // 保存(CSV形式)
    void save(std::ofstream& file) const {
        file << name << "," << phone << "," << email << std::endl;
    }
    
    // 読込(CSV形式)
    static Contact load(std::ifstream& file) {
        Contact c;
        std::getline(file, c.name, ',');
        std::getline(file, c.phone, ',');
        std::getline(file, c.email);
        return c;
    }
};



3. 住所録クラス

(1) 3.1 AddressBookクラスの定義

▶ サンプル 1:STLコンテナの使用(難易度 ⭐)

CPP 📖 参照専用
#include <vector>
#include <algorithm>

class AddressBook {
private:
    std::vector<Contact> contacts;

public:
    // 追加
    void addContact(const Contact& c) {
        contacts.push_back(c);
        std::cout << "追加しました!" << std::endl;
    }
    
    // 名前で検索
    Contact* findByName(const std::string& name) {
        for (auto& c : contacts) {
            if (c.getName() == name) {
                return &c;
            }
        }
        return nullptr;
    }
    
    // 名前で削除
    bool removeByName(const std::string& name) {
        auto it = std::remove_if(contacts.begin(), contacts.end(),
            [&name](const Contact& c) {
                return c.getName() == name;
            });
        
        if (it != contacts.end()) {
            contacts.erase(it, contacts.end());
            std::cout << "削除しました!" << std::endl;
            return true;
        }
        
        std::cout << "見つかりません:" << name << std::endl;
        return false;
    }
    
    // 全件表示
    void displayAll() const {
        if (contacts.empty()) {
            std::cout << "連絡先がありません..." << std::endl;
            return;
        }
        
        for (const auto& c : contacts) {
            c.display();
        }
    }
    
    // ファイルへ保存
    void saveToFile(const std::string& filename) const {
        std::ofstream file(filename);
        if (!file) {
            std::cerr << "ファイルを開けません..." << std::endl;
            return;
        }
        
        for (const auto& c : contacts) {
            c.save(file);
        }
        
        file.close();
        std::cout << "保存しました!" << std::endl;
    }
    
    // ファイルから読込
    void loadFromFile(const std::string& filename) {
        std::ifstream file(filename);
        if (!file) {
            std::cerr << "ファイルを開けません..." << std::endl;
            return;
        }
        
        contacts.clear(); // クリア
        
        std::string line;
        while (file.peek() != EOF) {
            contacts.push_back(Contact::load(file));
        }
        
        file.close();
        std::cout << "読み込みました!" << std::endl;
    }
};
論理コード 65 行(40 行制限超過、参照専用)


4. メニュー画面

(1) 4.1 実装

TEXT 📖 参照専用
void showMenu() {
    std::cout << "\n===== 住所録 =====" << std::endl;
    std::cout << "1. 追加" << std::endl;
    std::cout << "2. 削除" << std::endl;
    std::cout << "3. 検索" << std::endl;
    std::cout << "4. 一覧" << std::endl;
    std::cout << "5. 保存" << std::endl;
    std::cout << "6. 読込" << std::endl;
    std::cout << "0. 終了" << std::endl;
    std::cout << "==========================" << std::endl;
    std::cout << "選択:";
}

int main() {
    AddressBook book;
    int choice;
    
    do {
        showMenu();
        std::cin >> choice;
        
        switch (choice) {
            case 1: {
                std::string name, phone, email;
                std::cout << "名前:";
                std::cin >> name;
                std::cout << "電話:";
                std::cin >> phone;
                std::cout << "メール:";
                std::cin >> email;
                book.addContact(Contact(name, phone, email));
                break;
            }
            case 2: {
                std::string name;
                std::cout << "削除する名前:";
                std::cin >> name;
                book.removeByName(name);
                break;
            }
            case 3: {
                std::string name;
                std::cout << "検索する名前:";
                std::cin >> name;
                Contact* c = book.findByName(name);
                if (c) {
                    c->display();
                } else {
                    std::cout << "見つかりません..." << std::endl;
                }
                break;
            }
            case 4:
                book.displayAll();
                break;
            case 5: {
                book.saveToFile("contacts.txt");
                break;
            }
            case 6: {
                book.loadFromFile("contacts.txt");
                break;
            }
            case 0:
                std::cout << "終了します!" << std::endl;
                break;
            default:
                std::cout << "無効な選択..." << std::endl;
        }
    } while (choice != 0);
    
    return 0;
}



5. 拡張機能

(1) 5.1 機能一覧

機能 難易度
電話番号で検索
連絡先を変更 ⭐⭐
名前でソート ⭐⭐
インポート/エクスポートCSV ⭐⭐⭐
GUI ⭐⭐⭐⭐



6. 練習問題

(1) 初級(難易度 ⭐)

住所録に「電話番号で検索」機能を追加。

(2) 中級(難易度 ⭐⭐)

住所録に「変更」機能を追加。

(3) 上級(難易度 ⭐⭐⭐)

std::map で住所録をリファクタリングし、検索を高速化。



▶ サンプル 2:連絡先表示機能(難易度 ⭐⭐)

CPP
#include <iostream>
#include <string>
#include <vector>

struct Contact {
    std::string name;
    std::string phone;
    std::string email;
};

void displayContact(const Contact& c) {
    std::cout << "名前: " << c.name << std::endl;
    std::cout << "電話: " << c.phone << std::endl;
    std::cout << "メール: " << c.email << std::endl;
    std::cout << "-------------------" << std::endl;
}

void displayAllContacts(const std::vector<Contact>& contacts) {
    if (contacts.empty()) {
        std::cout << "連絡先がありません." << std::endl;
        return;
    }

    for (const auto& c : contacts) {
        displayContact(c);
    }
}

int main() {
    std::vector<Contact> contacts = {
        {"田中", "123-456-7890", "tanaka@email.com"},
        {"佐藤", "987-654-3210", "sato@email.com"}
    };

    displayAllContacts(contacts);

    return 0;
}
▶ 試してみよう

出力:

TEXT 📖 参照専用
名前: 田中
電話: 123-456-7890
メール: tanaka@email.com
-------------------
名前: 佐藤
電話: 987-654-3210
メール: sato@email.com
-------------------

▶ サンプル 3:電話番号で検索(難易度 ⭐⭐)

CPP
#include <iostream>
#include <string>
#include <vector>

struct Contact {
    std::string name;
    std::string phone;
    std::string email;
};

Contact* findByPhone(std::vector<Contact>& contacts, const std::string& phone) {
    for (auto& c : contacts) {
        if (c.phone == phone) {
            return &c;
        }
    }
    return nullptr;
}

int main() {
    std::vector<Contact> contacts = {
        {"田中", "1234567890", "tanaka@email.com"},
        {"佐藤", "9876543210", "sato@email.com"},
        {"鈴木", "5555555555", "suzuki@email.com"}
    };

    std::string searchTerm = "9876543210";
    Contact* found = findByPhone(contacts, searchTerm);

    if (found) {
        std::cout << "見つかりました: " << found->name << " (" << found->phone << ")" << std::endl;
    } else {
        std::cout << "連絡先が見つかりません" << std::endl;
    }

    return 0;
}
▶ 試してみよう

出力:

TEXT 📖 参照専用
見つかりました: 佐藤 (9876543210)

❓ よくある質問

Q:住所録プロジェクトで最も重要なことは? A:まず核心概念を理解し、実践例で練習することです。

Q:住所録を効果的に練習するには? A:シンプルな例から始め、徐々に複雑さを増やし、常にコードをテストしてください。

Q:よくある間違いは? A:コンパイラのエラーメッセージを注意深く読み、常に変数を初期化してから使用してください。


📖 まとめ

トピック 応用
オブジェクト指向 ContactとAddressBookクラス
STL vector
ファイル入出力 保存/読込
文字列処理 CSV

📝 練習問題

  1. 初級(難易度 ⭐): 住所録プログラムを拡張し、3つの連絡先(名前、電話、メール)を追加し、「一覧」機能で出力。その後「検索」機能で特定の連絡先を変更。

  2. 中級(難易度 ⭐⭐): 住所録に「お気に入り」機能を追加——structに bool isFavorite を追加、一覧で [★] を表示。

  3. 上級(難易度 ⭐⭐⭐): 「バリデーション」機能を実装:ユーザー入力で、電話番号が数字のみか、メールに@が含まれるかを検証。不正入力の場合はエラーメッセージを表示。


次のレッスン:プロジェクト:データベース(#52)

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%