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;
}
};
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 |
- 住所録システム:追加/削除/検索/一覧機能
- structでデータを定義
- vectorコンテナで動的なデータを管理
- ファイル入出力でデータを永続化
- モジュラー関数で機能をカプセル化
📝 練習問題
-
初級(難易度 ⭐): 住所録プログラムを拡張し、3つの連絡先(名前、電話、メール)を追加し、「一覧」機能で出力。その後「検索」機能で特定の連絡先を変更。
-
中級(難易度 ⭐⭐): 住所録に「お気に入り」機能を追加——structに
bool isFavoriteを追加、一覧で[★]を表示。 -
上級(難易度 ⭐⭐⭐): 「バリデーション」機能を実装:ユーザー入力で、電話番号が数字のみか、メールに@が含まれるかを検証。不正入力の場合はエラーメッセージを表示。
次のレッスン:プロジェクト:データベース(#52)