以下はC++を用いたオブジェクト指向設計とリソース管理の実装例についての詳細です。各タスクでは、クラス設計、メモリ管理、カプセル化の実践を通じて、効率的で安全なコード作成の手法を学びます。
タスク1:GUIコンポーネントの実装
#pragma once
#include <iostream>
#include <string>
class PushButton {
public:
PushButton(const std::string& text);
const std::string& getText() const;
void activate();
private:
std::string text_;
};
#include "window_manager.hpp"
#include <iostream>
void demo() {
WindowManager w("サンプル");
w.addControl("追加");
w.addControl("削除");
w.addControl("変更");
w.addControl("追加");
w.show();
w.close();
}
int main() {
std::cout << "コンポジションによるGUIシミュレーション:\n";
demo();
}
#pragma once
#include <iostream>
#include <vector>
#include <algorithm>
#include "pushbutton.hpp"
class WindowManager {
public:
WindowManager(const std::string& title);
void show() const;
void close();
void addControl(const std::string& label);
void triggerControl(const std::string& label);
private:
bool hasControl(const std::string& label) const;
private:
std::string title_;
std::vector<PushButton> controls;
};
タスク2:深コピーの検証
#include <iostream>
#include <vector>
void verifyCopy1();
void verifyCopy2();
void printVector(const std::vector<int>& v);
void printNestedVector(const std::vector<std::vector<int>>& v);
int main() {
std::cout << "深コピー検証1: std::vector<int>\n";
verifyCopy1();
std::cout << "\n深コピー検証2: ネストされたstd::vector<int>\n";
verifyCopy2();
}
void verifyCopy1() {
std::vector<int> v1(5, 42);
const std::vector<int> v2(v1);
std::cout << "--- コピー後 ---\n";
std::cout << "v1: "; printVector(v1);
std::cout << "v2: "; printVector(v2);
v1[0] = -1;
std::cout << "--- v1[0]変更後 ---\n";
std::cout << "v1: "; printVector(v1);
std::cout << "v2: "; printVector(v2);
}
void verifyCopy2() {
std::vector<std::vector<int>> v1{{1, 2, 3}, {4, 5, 6, 7}};
const std::vector<std::vector<int>> v2(v1);
std::cout << "--- コピー後 ---\n";
std::cout << "v1: "; printNestedVector(v1);
std::cout << "v2: "; printNestedVector(v2);
v1[0].push_back(-1);
std::cout << "--- v1[0]変更後 ---\n";
std::cout << "v1: "; printNestedVector(v1);
std::cout << "v2: "; printNestedVector(v2);
}
void printVector(const std::vector<int>& v) {
if (v.empty()) {
std::cout << '\n';
return;
}
std::cout << v[0];
for (size_t i = 1; i < v.size(); ++i)
std::cout << ", " << v[i];
std::cout << '\n';
}
void printNestedVector(const std::vector<std::vector<int>>& v) {
for (const auto& row : v) {
printVector(row);
}
}
タスク3:独自のベクターコンテナの実装
#pragma once
#include <iostream>
class IntVector {
public:
IntVector();
IntVector(int size);
IntVector(int size, int value);
IntVector(const IntVector& other);
~IntVector();
int getSize() const;
int& getAt(int index);
const int& getAt(int index) const;
IntVector& assign(const IntVector& other);
int* begin();
int* end();
const int* begin() const;
const int* end() const;
private:
int size_;
int* data_;
};
#include "intvector.hpp"
#include <iostream>
void test1();
void test2();
void display1(const IntVector& vec);
void display2(const IntVector& vec);
int main() {
std::cout << "テスト1:\n";
test1();
std::cout << "\nテスト2:\n";
test2();
}
void test1() {
int n;
std::cout << "サイズを入力: ";
std::cin >> n;
IntVector x1(n);
for (int i = 0; i < n; ++i)
x1.getAt(i) = (i + 1) * 10;
std::cout << "x1: "; display1(x1);
IntVector x2(n, 42);
IntVector x3(x2);
x2.getAt(0) = -1;
std::cout << "x2: "; display1(x2);
std::cout << "x3: "; display1(x3);
}
void test2() {
const IntVector x(5, 42);
IntVector y;
y.assign(x);
std::cout << "x: "; display2(x);
std::cout << "y: "; display2(y);
}
void display1(const IntVector& vec) {
if (vec.getSize() == 0) {
std::cout << '\n';
return;
}
std::cout << vec.getAt(0);
for (int i = 1; i < vec.getSize(); ++i)
std::cout << ", " << vec.getAt(i);
std::cout << '\n';
}
void display2(const IntVector& vec) {
if (vec.getSize() == 0) {
std::cout << '\n';
return;
}
auto it = vec.begin();
std::cout << *it;
for (it = vec.begin() + 1; it != vec.end(); ++it)
std::cout << ", " << *it;
std::cout << '\n';
}
タスク4:行列クラスの実装
#pragma once
#include <iostream>
#include <algorithm>
#include <cstdlib>
class Matrix {
public:
Matrix(int rows, int cols, double value = 0);
Matrix(int size, double value = 0);
Matrix(const Matrix& other);
~Matrix();
void setData(const double* values, int size);
void clear();
const double& at(int row, int col) const;
double& at(int row, int col);
int getRows() const;
int getCols() const;
void print() const;
private:
int rows_;
int cols_;
double* data_;
};
#include "matrix.hpp"
#include <iostream>
#include <cstring>
Matrix::Matrix(int rows, int cols, double value)
: rows_(rows), cols_(cols), data_(new double[rows * cols]) {
if (rows <= 0 || cols <= 0) {
std::cerr << "エラー: 無効な行列サイズ" << std::endl;
std::exit(1);
}
for (int i = 0; i < rows * cols; ++i)
data_[i] = value;
}
Matrix::Matrix(int size, double value)
: Matrix(size, size, value) {}
Matrix::Matrix(const Matrix& other)
: rows_(other.rows_), cols_(other.cols_), data_(new double[rows_ * cols_]) {
std::memcpy(data_, other.data_, rows_ * cols_ * sizeof(double));
}
Matrix::~Matrix() {
delete[] data_;
}
void Matrix::setData(const double* values, int size) {
if (size != rows_ * cols_) {
std::cerr << "エラー: サイズ不一致" << std::endl;
std::exit(1);
}
std::memcpy(data_, values, size * sizeof(double));
}
void Matrix::clear() {
for (int i = 0; i < rows_ * cols_; ++i)
data_[i] = 0.0;
}
const double& Matrix::at(int row, int col) const {
if (row < 0 || row >= rows_ || col < 0 || col >= cols_) {
std::cerr << "エラー: インデックス範囲外" << std::endl;
std::exit(1);
}
return data_[row * cols_ + col];
}
double& Matrix::at(int row, int col) {
if (row < 0 || row >= rows_ || col < 0 || col >= cols_) {
std::cerr << "エラー: インデックス範囲外" << std::endl;
std::exit(1);
}
return data_[row * cols_ + col];
}
int Matrix::getRows() const {
return rows_;
}
int Matrix::getCols() const {
return cols_;
}
void Matrix::print() const {
for (int i = 0; i < rows_; ++i) {
std::cout << at(i, 0);
for (int j = 1; j < cols_; ++j)
std::cout << ", " << at(i, j);
std::cout << '\n';
}
}
タスク5:連絡先管理アプリケーション
#pragma once
#include <iostream>
#include <string>
class Contact {
public:
Contact(const std::string& name, const std::string& phone);
const std::string& getName() const;
const std::string& getPhone() const;
void show() const;
private:
std::string name_;
std::string phone_;
};
#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include "contact.hpp"
class ContactBook {
public:
void add(const std::string& name, const std::string& phone);
void remove(const std::string& name);
void search(const std::string& name) const;
void display() const;
size_t count() const;
private:
int findIndex(const std::string& name) const;
void sortByName();
private:
std::vector<Contact> contacts_;
};
#include "contactbook.hpp"
void test() {
ContactBook book;
std::cout << "1. 連絡先を追加\n";
book.add("Bob", "18199357253");
book.add("Alice", "17300886371");
book.add("Linda", "18184538072");
book.add("Alice", "17300886371");
std::cout << "\n2. 連絡先を表示\n";
std::cout << "合計: " << book.count() << "件\n";
book.display();
std::cout << "\n3. 連絡先を検索\n";
book.search("Bob");
book.search("David");
std::cout << "\n4. 連絡先を削除\n";
book.remove("Bob");
book.remove("David");
}
int main() {
test();
}
まとめ
C++におけるオブジェクト指向設計は、単なる構文の利用ではなく、問題をオブジェクトとして抽象化する思考プロセスです。RAII原則を活用したリソース管理により、メモリ漏れやエラーを防ぎつつ、パフォーマンスを維持できます。また、インターフェース設計の際には、カプセル化を適切に維持し、公開範囲を最小限に抑えることで、コードの保守性と拡張性を向上させることができます。
6月3日 21:30 投稿