[C#] クラスの基本をわかりやすく解説
C#におけるクラスは、オブジェクト指向プログラミングの基本構造であり、データとメソッドをまとめて扱うためのテンプレートです。
クラスは、フィールド(データ)とメソッド(操作)を含むことができ、これによりデータのカプセル化と再利用が可能になります。
クラスは「型」として機能し、インスタンス化することでオブジェクトを生成します。
クラスの定義には、アクセス修飾子(例:public, private)を用いてメンバーの可視性を制御し、コンストラクタを使用してオブジェクトの初期化を行います。
クラスは継承を通じて他のクラスの機能を拡張することも可能です。
クラスとは何か
クラスの基本
クラスは、C#におけるオブジェクト指向プログラミングの基盤となる概念です。
クラスは、データとそのデータを操作するメソッドをまとめたテンプレートとして機能します。
クラスを定義することで、同じ構造を持つオブジェクトを複数生成することができます。
以下は、基本的なクラスの定義例です。
// 人を表すクラス
public class Person
{
// 名前を格納するフィールド
private string name;
// 年齢を格納するフィールド
private int age;
// コンストラクタ
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
// 名前を取得するメソッド
public string GetName()
{
return name;
}
// 年齢を取得するメソッド
public int GetAge()
{
return age;
}
}
この例では、Person
というクラスを定義し、name
とage
というフィールドを持たせています。
また、コンストラクタを用いてオブジェクトの初期化を行い、GetName
とGetAge
というメソッドでフィールドの値を取得できるようにしています。
オブジェクト指向プログラミングにおけるクラスの役割
オブジェクト指向プログラミング(OOP)において、クラスは以下のような役割を果たします。
- データのカプセル化: クラスはデータとその操作を一つにまとめ、外部からの不正なアクセスを防ぎます。
- 再利用性の向上: 一度定義したクラスは、他のプログラムでも再利用可能です。
- コードの整理: クラスを使うことで、関連するデータとメソッドを一つの単位として整理できます。
クラスとオブジェクトの違い
クラスとオブジェクトは、オブジェクト指向プログラミングにおいて重要な概念ですが、異なる役割を持っています。
用語 | 説明 |
---|---|
クラス | オブジェクトの設計図。データとメソッドを定義するテンプレート。 |
オブジェクト | クラスから生成された実体。クラスのインスタンスとも呼ばれる。 |
クラスは設計図であり、オブジェクトはその設計図に基づいて生成された具体的な実体です。
例えば、Personクラス
を使って複数のPerson
オブジェクトを生成することができます。
以下は、Personクラス
を使ってオブジェクトを生成する例です。
// Mainメソッド内でのオブジェクト生成
Person person1 = new Person("太郎", 30);
Person person2 = new Person("花子", 25);
// オブジェクトの情報を出力
Console.WriteLine("名前: " + person1.GetName() + ", 年齢: " + person1.GetAge());
Console.WriteLine("名前: " + person2.GetName() + ", 年齢: " + person2.GetAge());
名前: 太郎, 年齢: 30
名前: 花子, 年齢: 25
この例では、Personクラス
からperson1
とperson2
という2つのオブジェクトを生成し、それぞれの情報を出力しています。
クラスは設計図としての役割を果たし、オブジェクトはその設計図に基づいて具体的なデータを持つ実体となります。
クラスの構成要素
フィールドとプロパティ
フィールドは、クラス内でデータを保持するための変数です。
フィールドはクラスのインスタンスごとに異なる値を持つことができます。
以下はフィールドの例です。
// 人を表すクラス
public class Person
{
// 名前を格納するフィールド
private string name;
// 年齢を格納するフィールド
private int age;
}
プロパティは、フィールドへのアクセスを制御するためのメカニズムです。
プロパティを使うことで、フィールドの値を取得したり設定したりする際に追加のロジックを実行できます。
// 人を表すクラス
public class Person
{
// 名前を格納するフィールド
private string name;
// 年齢を格納するフィールド
private int age;
// 名前を取得・設定するプロパティ
public string Name
{
get { return name; }
set { name = value; }
}
// 年齢を取得・設定するプロパティ
public int Age
{
get { return age; }
set { age = value; }
}
}
メソッド
メソッドは、クラス内で特定の動作を実行するための関数です。
メソッドはクラスのインスタンスに対して操作を行うことができます。
// 人を表すクラス
public class Person
{
private string name;
private int age;
// コンストラクタ
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
// 名前を取得するメソッド
public string GetName()
{
return name;
}
// 年齢を取得するメソッド
public int GetAge()
{
return age;
}
// 自己紹介を行うメソッド
public void Introduce()
{
Console.WriteLine("こんにちは、私の名前は" + name + "です。年齢は" + age + "歳です。");
}
}
コンストラクタ
コンストラクタは、クラスのインスタンスが生成される際に呼び出される特別なメソッドです。
コンストラクタは、オブジェクトの初期化を行うために使用されます。
// 人を表すクラス
public class Person
{
private string name;
private int age;
// コンストラクタ
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
}
コンストラクタはクラス名と同じ名前を持ち、戻り値を持ちません。
上記の例では、Personクラス
のコンストラクタがname
とage
を初期化しています。
アクセス修飾子
アクセス修飾子は、クラスやそのメンバー(フィールド、プロパティ、メソッドなど)のアクセス範囲を制御するために使用されます。
C#で一般的に使用されるアクセス修飾子には以下のものがあります。
アクセス修飾子 | 説明 |
---|---|
public | どこからでもアクセス可能 |
private | クラス内からのみアクセス可能 |
protected | クラス内および派生クラスからアクセス可能 |
internal | 同一アセンブリ内からアクセス可能 |
protected internal | 同一アセンブリ内または派生クラスからアクセス可能 |
以下は、アクセス修飾子を使用した例です。
// 人を表すクラス
public class Person
{
// privateフィールド
private string name;
// publicプロパティ
public string Name
{
get { return name; }
set { name = value; }
}
// publicメソッド
public void Introduce()
{
Console.WriteLine("こんにちは、私の名前は" + name + "です。");
}
}
この例では、name
フィールドはprivate
として定義されており、クラス外から直接アクセスすることはできませんが、Name
プロパティを通じてアクセスが可能です。
Introduceメソッド
はpublic
として定義されており、クラス外からも呼び出すことができます。
クラスの作成と使用
クラスの定義方法
C#でクラスを定義するには、class
キーワードを使用します。
クラスの定義には、クラス名、フィールド、プロパティ、メソッドなどを含めることができます。
以下は、基本的なクラスの定義方法の例です。
// 車を表すクラス
public class Car
{
// 車のモデル名を格納するフィールド
private string model;
// 車の速度を格納するフィールド
private int speed;
// コンストラクタ
public Car(string model, int speed)
{
this.model = model;
this.speed = speed;
}
// モデル名を取得するプロパティ
public string Model
{
get { return model; }
set { model = value; }
}
// 速度を取得するプロパティ
public int Speed
{
get { return speed; }
set { speed = value; }
}
// 車の情報を表示するメソッド
public void DisplayInfo()
{
Console.WriteLine("モデル: " + model + ", 速度: " + speed + " km/h");
}
}
この例では、Car
というクラスを定義し、model
とspeed
というフィールドを持たせています。
また、コンストラクタを用いてオブジェクトの初期化を行い、Model
とSpeed
というプロパティでフィールドの値を取得・設定できるようにしています。
インスタンス化とオブジェクトの生成
クラスを使用するためには、まずそのクラスのインスタンスを生成する必要があります。
これをインスタンス化と呼びます。
インスタンス化は、new
キーワードを使用して行います。
// Mainメソッド内でのオブジェクト生成
Car car1 = new Car("トヨタ", 120);
Car car2 = new Car("ホンダ", 150);
この例では、Carクラス
からcar1
とcar2
という2つのオブジェクトを生成しています。
それぞれのオブジェクトは、Carクラス
のインスタンスです。
メンバーへのアクセス
クラスのインスタンスを生成した後は、そのインスタンスのメンバー(フィールド、プロパティ、メソッド)にアクセスすることができます。
メンバーへのアクセスは、ドット演算子.
を使用して行います。
// オブジェクトのメンバーにアクセス
car1.DisplayInfo();
car2.DisplayInfo();
// プロパティを使用して値を取得・設定
Console.WriteLine("car1のモデル: " + car1.Model);
car1.Speed = 130;
Console.WriteLine("car1の新しい速度: " + car1.Speed);
モデル: トヨタ, 速度: 120 km/h
モデル: ホンダ, 速度: 150 km/h
car1のモデル: トヨタ
car1の新しい速度: 130
この例では、car1
とcar2
のDisplayInfoメソッド
を呼び出して、それぞれの車の情報を表示しています。
また、Model
プロパティを使用してcar1
のモデル名を取得し、Speed
プロパティを使用して速度を変更しています。
これにより、クラスのメンバーにアクセスして操作を行うことができます。
クラスの継承と多態性
継承の基本
継承は、既存のクラス(基底クラスまたは親クラス)の機能を引き継いで、新しいクラス(派生クラスまたは子クラス)を作成するための機能です。
継承を使用することで、コードの再利用性を高め、クラス間の関係を明確にすることができます。
以下は、継承の基本的な例です。
// 基底クラス
public class Animal
{
public void Eat()
{
Console.WriteLine("食べる");
}
}
// 派生クラス
public class Dog : Animal
{
public void Bark()
{
Console.WriteLine("吠える");
}
}
この例では、Animalクラス
が基底クラスであり、Dogクラス
がAnimalクラス
を継承しています。
Dogクラス
はAnimalクラス
のEatメソッド
を引き継ぎつつ、新たにBarkメソッド
を追加しています。
オーバーライドとオーバーロード
オーバーライドは、基底クラスのメソッドを派生クラスで再定義することです。
オーバーライドを行うには、基底クラスのメソッドにvirtual
キーワードを付け、派生クラスのメソッドにoverride
キーワードを付けます。
// 基底クラス
public class Animal
{
public virtual void Speak()
{
Console.WriteLine("動物の声");
}
}
// 派生クラス
public class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("ワンワン");
}
}
この例では、Animalクラス
のSpeakメソッド
をDogクラス
でオーバーライドしています。
Dogクラス
のSpeakメソッド
は、Animalクラス
のSpeakメソッド
を上書きしています。
オーバーロードは、同じ名前のメソッドを異なる引数リストで定義することです。
オーバーロードは、メソッドの引数の数や型を変えることで実現します。
public class Calculator
{
// メソッドのオーバーロード
public int Add(int a, int b)
{
return a + b;
}
public double Add(double a, double b)
{
return a + b;
}
}
この例では、Addメソッド
が整数と浮動小数点数の両方に対してオーバーロードされています。
抽象クラスとインターフェース
抽象クラスは、インスタンス化できないクラスであり、他のクラスに継承されることを目的としています。
抽象クラスは、少なくとも一つの抽象メソッドを持ちます。
抽象メソッドは、派生クラスで実装される必要があります。
// 抽象クラス
public abstract class Animal
{
public abstract void Speak();
}
// 派生クラス
public class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("ワンワン");
}
}
この例では、Animalクラス
が抽象クラスであり、Speakメソッド
が抽象メソッドとして定義されています。
Dogクラス
はAnimalクラス
を継承し、Speakメソッド
を実装しています。
インターフェースは、クラスが実装すべきメソッドのシグネチャを定義するためのものです。
インターフェースは、クラスに特定の機能を持たせるための契約のようなものです。
// インターフェース
public interface IFlyable
{
void Fly();
}
// クラスがインターフェースを実装
public class Bird : IFlyable
{
public void Fly()
{
Console.WriteLine("飛ぶ");
}
}
この例では、IFlyable
インターフェースがFlyメソッド
を定義しており、Birdクラス
がこのインターフェースを実装しています。
インターフェースを使用することで、異なるクラスに共通の機能を持たせることができます。
クラスの応用例
クラスを使ったデータモデルの設計
クラスは、データモデルを設計する際に非常に有用です。
データモデルとは、特定のドメインにおけるデータの構造を表現するものです。
クラスを使うことで、データとその操作を一つの単位としてまとめることができます。
以下は、クラスを使ったシンプルなデータモデルの例です。
// 商品を表すクラス
public class Product
{
// 商品名を格納するフィールド
private string name;
// 価格を格納するフィールド
private decimal price;
// コンストラクタ
public Product(string name, decimal price)
{
this.name = name;
this.price = price;
}
// 商品名を取得するプロパティ
public string Name
{
get { return name; }
set { name = value; }
}
// 価格を取得するプロパティ
public decimal Price
{
get { return price; }
set { price = value; }
}
// 商品情報を表示するメソッド
public void DisplayInfo()
{
Console.WriteLine("商品名: " + name + ", 価格: " + price + "円");
}
}
この例では、Productクラス
を使って商品データをモデル化しています。
name
とprice
というフィールドを持ち、商品情報を表示するDisplayInfoメソッド
を提供しています。
クラスを用いたデザインパターンの実装
クラスは、デザインパターンを実装する際にも重要な役割を果たします。
デザインパターンは、特定の問題に対する一般的な解決策を提供するもので、クラスを使って実装されることが多いです。
以下は、シングルトンパターンの実装例です。
シングルトンパターンは、クラスのインスタンスが一つだけであることを保証するデザインパターンです。
// シングルトンパターンを実装したクラス
public class Singleton
{
// 唯一のインスタンスを保持するフィールド
private static Singleton instance;
// コンストラクタをprivateにして外部からのインスタンス化を防ぐ
private Singleton() { }
// インスタンスを取得するメソッド
public static Singleton GetInstance()
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
// シングルトンの動作を確認するメソッド
public void ShowMessage()
{
Console.WriteLine("シングルトンインスタンスです。");
}
}
この例では、Singletonクラス
がシングルトンパターンを実装しています。
GetInstanceメソッド
を通じて唯一のインスタンスを取得し、ShowMessageメソッド
でメッセージを表示します。
クラスを活用したコードの再利用性向上
クラスを活用することで、コードの再利用性を向上させることができます。
クラスを一度定義すれば、異なるプロジェクトやコンポーネントで再利用することが可能です。
以下は、クラスを使って共通の機能を提供するユーティリティクラスの例です。
// 数学的な操作を提供するユーティリティクラス
public static class MathUtilities
{
// 2つの数値の最大公約数を計算するメソッド
public static int GCD(int a, int b)
{
while (b != 0)
{
int temp = b;
b = a % b;
a = temp;
}
return a;
}
// 2つの数値の最小公倍数を計算するメソッド
public static int LCM(int a, int b)
{
return (a / GCD(a, b)) * b;
}
}
この例では、MathUtilitiesクラス
が数学的な操作を提供しています。
GCDメソッド
で最大公約数を計算し、LCMメソッド
で最小公倍数を計算します。
このようなユーティリティクラスを作成することで、共通の機能を簡単に再利用することができます。
まとめ
この記事では、C#におけるクラスの基本から、その構成要素、継承と多態性、さらには応用例までを詳しく解説しました。
クラスを用いることで、オブジェクト指向プログラミングの利点を活かし、コードの再利用性や保守性を高めることが可能です。
これを機に、実際のプロジェクトでクラスを活用し、より効率的で柔軟なプログラム設計に挑戦してみてください。