クラスとオブジェクト
オブジェクト指向プログラミングの核心概念
オブジェクト指向プログラミング(OOP)は、現実世界のエンティティを「オブジェクト」としてモデル化し、それらを共通の特徴に基づいて「クラス」に抽象化する手法です。その4大原則は以下の通りです:
- 抽象化:本質的な特徴のみを抽出し、不要な詳細を隠蔽
- カプセル化:データと操作を1つの単位にまとめる
- 継承:既存のクラスの特性を再利用
- 多態性:同じインターフェースで異なる動作を実現
クラスの定義と構造
C++ではclassキーワードを使用してクラスを定義します:
class Computer {
private:
char _brand[20];
double _price;
public:
void setBrand(const char* brand) {
strncpy(_brand, brand, sizeof(_brand) - 1);
_brand[sizeof(_brand) - 1] = '\0';
}
double getPrice() const { return _price; }
};
アクセス修飾子
- public:外部から直接アクセス可能
- protected:派生クラスからのみアクセス可能
- private:クラス内部からのみアクセス可能(デフォルト)
class vs struct
C++においては、classのデフォルトアクセス権はprivateですが、structのデフォルトはpublicです。機能的にはほぼ同等です。
コンストラクタと初期化
コンストラクタはオブジェクト生成時に自動的に呼び出され、メンバー変数の初期化を担当します:
class Point {
private:
int _x, _y;
public:
// デフォルトコンストラクタ
Point() : _x(0), _y(0) {}
// パラメータ付きコンストラクタ
Point(int x, int y) : _x(x), _y(y) {}
// 初期化リストを使用した効率的な初期化
};
デストラクタとリソース管理
デストラクタはオブジェクト破棄時に自動的に呼び出され、動的メモリなどのリソースを解放します:
class DynamicString {
private:
char* _data;
public:
DynamicString(const char* str) {
_data = new char[strlen(str) + 1];
strcpy(_data, str);
}
~DynamicString() {
delete[] _data;
_data = nullptr;
}
};
コピーコンストラクタと代入演算子
ポインタメンバーを持つクラスでは、ディープコピーを実装する必要があります:
class DeepCopyExample {
private:
char* _buffer;
public:
// コピーコンストラクタ(ディープコピー)
DeepCopyExample(const DeepCopyExample& other) {
_buffer = new char[strlen(other._buffer) + 1];
strcpy(_buffer, other._buffer);
}
// 代入演算子(自己代入チェック付き)
DeepCopyExample& operator=(const DeepCopyExample& other) {
if (this != &other) {
delete[] _buffer;
_buffer = new char[strlen(other._buffer) + 1];
strcpy(_buffer, other._buffer);
}
return *this;
}
};
特殊なメンバー関数
constメンバー関数
オブジェクトの状態を変更しないメンバー関数にはconst修飾子を付与します:
class Rectangle {
private:
double _width, _height;
public:
double getArea() const {
return _width * _height; // 状態を変更しない
}
};
スタティックメンバー関数
特定のオブジェクトインスタンスに依存しない関数はスタティックとして定義します:
class Counter {
private:
static int _count;
public:
static int getCount() { return _count; }
Counter() { ++_count; }
};
int Counter::_count = 0;
シングルトンパターン
システム内で唯一のインスタンスを保証するデザインパターンです:
class Singleton {
private:
static Singleton* _instance;
Singleton() = default;
~Singleton() = default;
// コピーと代入を禁止
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
public:
static Singleton* getInstance() {
if (!_instance) {
_instance = new Singleton();
}
return _instance;
}
static void destroy() {
delete _instance;
_instance = nullptr;
}
};
Singleton* Singleton::_instance = nullptr;
std::stringとstd::vector
std::stringの利点
Cスタイル文字列よりも安全で使いやすい文字列処理クラスです:
#include <string>
void stringExample() {
std::string greeting = "Hello";
greeting += " World!";
// 安全なアクセス
if (!greeting.empty()) {
std::cout << greeting.at(0); // 境界チェックあり
}
}
std::vectorの動的配列
自動的にサイズ調整される動的配列コンテナです:
#include <vector>
void vectorExample() {
std::vector<int> numbers;
numbers.reserve(100); // 事前メモリ確保
for (int i = 0; i < 10; ++i) {
numbers.push_back(i * i);
}
// 範囲forループによる走査
for (const auto& num : numbers) {
std::cout << num << " ";
}
}