C#のクラス完全ガイド:定義・カプセル化・コンストラクタ・デストラクタ・静的メンバー
クラスを定義するとき、データ型の青写真(ブループリント)を定義します。これは実際のデータを定義するものではなく、クラス名が何を意味するか、つまりクラスのオブジェクトが何で構成され、そのオブジェクトで何の操作を実行できるかを定義します。オブジェクトはクラスのインスタンスです。クラスを構成するメソッドと変数は、クラスのメンバーと呼ばれます。
クラスの定義
クラス定義はclassキーワードで始まり、クラス名、波括弧で囲まれたクラス本体が続きます。
<access specifier> class class_name {
// メンバ変数
<access specifier> <data type> variable1;
<access specifier> <data type> variable2;
...
// メンバメソッド
<access specifier> <return type> method1(parameter_list) {
// method body
}
...
}
注意点
- アクセス修飾子はメンバーおよびクラス自体のアクセス規則を指定。未指定時、クラスのデフォルトは
internal、メンバーのデフォルトはprivate - データ型は変数の型、戻り値の型はメソッドが返すデータの型
- クラスメンバーにアクセスするにはドット(.)演算子を使用
- ドット演算子はオブジェクト名とメンバー名を結びつける
基本的なクラス定義の例
using System;
namespace BoxApplication {
class Box {
public double length;
public double breadth;
public double height;
}
class BoxTester {
static void Main(string[] args) {
Box box1 = new Box();
Box box2 = new Box();
double volume = 0.0;
// box1の仕様
box1.height = 5.0;
box1.length = 6.0;
box1.breadth = 7.0;
// box2の仕様
box2.height = 10.0;
box2.length = 12.0;
box2.breadth = 13.0;
// box1の体積
volume = box1.height * box1.length * box1.breadth;
Console.WriteLine("Volume of Box1 : {0}", volume);
// box2の体積
volume = box2.height * box2.length * box2.breadth;
Console.WriteLine("Volume of Box2 : {0}", volume);
Console.ReadKey();
}
}
}
実行結果:
Volume of Box1 : 210
Volume of Box2 : 1560
メンバ関数とカプセル化
クラスのメンバ関数とは、クラス定義内で定義またはプロトタイプ宣言された関数です。そのクラスのオブジェクトで動作し、そのオブジェクトのすべてのメンバーにアクセスできます。
メンバ変数はオブジェクトの属性(設計の観点から)であり、カプセル化を実現するためにprivateに保持されます。これらの変数にはパブリックなメンバ関数を通じてのみアクセスできます。
カプセル化の例(セッター/ゲッター)
using System;
namespace BoxApplication {
class Box {
private double length;
private double breadth;
private double height;
public void SetLength(double len) { length = len; }
public void SetBreadth(double bre) { breadth = bre; }
public void SetHeight(double hei) { height = hei; }
public double GetVolume() {
return length * breadth * height;
}
}
class BoxTester {
static void Main(string[] args) {
Box box1 = new Box();
Box box2 = new Box();
double volume;
box1.SetLength(6.0);
box1.SetBreadth(7.0);
box1.SetHeight(5.0);
box2.SetLength(12.0);
box2.SetBreadth(13.0);
box2.SetHeight(10.0);
volume = box1.GetVolume();
Console.WriteLine("Volume of Box1 : {0}", volume);
volume = box2.GetVolume();
Console.WriteLine("Volume of Box2 : {0}", volume);
Console.ReadKey();
}
}
}
C#コンストラクタ
クラスのコンストラクタは、そのクラスの新しいオブジェクトが作成されるたびに実行される特殊なメンバ関数です。
- クラスと同じ名前を持つ
- 戻り値の型を持たない(
voidも書かない) - パラメータを持つことも持たないこともある
デフォルトコンストラクタの例
using System;
namespace LineApplication {
class Line {
private double length;
public Line() { // デフォルトコンストラクタ
Console.WriteLine("Object is being created");
}
public void SetLength(double len) { length = len; }
public double GetLength() { return length; }
static void Main(string[] args) {
Line line = new Line();
line.SetLength(6.0);
Console.WriteLine("Length of line : {0}", line.GetLength());
Console.ReadKey();
}
}
}
実行結果:
Object is being created
Length of line : 6
パラメータ付きコンストラクタの例
using System;
namespace LineApplication {
class Line {
private double length;
public Line(double len) { // パラメータ付きコンストラクタ
Console.WriteLine("Object is being created, length = {0}", len);
length = len;
}
public void SetLength(double len) { length = len; }
public double GetLength() { return length; }
static void Main(string[] args) {
Line line = new Line(10.0);
Console.WriteLine("Length of line : {0}", line.GetLength());
line.SetLength(6.0);
Console.WriteLine("Length of line : {0}", line.GetLength());
Console.ReadKey();
}
}
}
実行結果:
Object is being created, length = 10
Length of line : 10
Length of line : 6
C#デストラクタ
デストラクタは、そのクラスのオブジェクトがスコープを外れるときに実行される特殊なメンバ関数です。
- クラス名と同じ名前でチルダ(
~)をプレフィックスとして持つ - 戻り値を持たず、パラメータも取れない
- 継承もオーバーロードもできない
- プログラム終了前のメモリリソース解放に有用
デストラクタの例
using System;
namespace LineApplication {
class Line {
private double length;
public Line() {
Console.WriteLine("Object is being created");
}
~Line() { // デストラクタ
Console.WriteLine("Object is being deleted");
}
public void SetLength(double len) { length = len; }
public double GetLength() { return length; }
static void Main(string[] args) {
Line line = new Line();
line.SetLength(6.0);
Console.WriteLine("Length of line : {0}", line.GetLength());
}
}
}
実行結果:
Object is being created
Length of line : 6
Object is being deleted
注意:C#ではデストラクタはガベージコレクタによって非決定的に呼び出されます。確実なリソース解放にはIDisposableパターンとusingステートメントを使用するのが推奨されます。
静的メンバー
staticキーワードでクラスメンバーを静的に定義できます。クラスのオブジェクトが何個作成されても、静的メンバーのコピーは1つだけ存在します。
静的変数の例
using System;
namespace StaticVarApplication {
class StaticVar {
public static int num;
public void Count() { num++; }
public int GetNum() { return num; }
}
class StaticTester {
static void Main(string[] args) {
StaticVar s1 = new StaticVar();
StaticVar s2 = new StaticVar();
s1.Count(); s1.Count(); s1.Count();
s2.Count(); s2.Count(); s2.Count();
Console.WriteLine("Variable num for s1: {0}", s1.GetNum()); // 6
Console.WriteLine("Variable num for s2: {0}", s2.GetNum()); // 6(共有)
Console.ReadKey();
}
}
}
静的メソッドの例
class StaticVar {
public static int num;
public void Count() { num++; }
public static int GetNum() { return num; } // 静的メソッド
}
static void Main() {
StaticVar s = new StaticVar();
s.Count(); s.Count(); s.Count();
Console.WriteLine("Variable num: {0}", StaticVar.GetNum()); // クラス名で呼び出し
// 3
}
静的コンストラクタ
静的フィールドの初期化や、一度だけ実行する処理に使用します。
class MyClass {
static MyClass() {
// 静的初期化(最初のアクセス前に1回だけ実行)
}
}
readonlyフィールドとconstの違い
| const | readonly | |
|---|---|---|
| 初期化 | 宣言時のみ | 宣言時またはコンストラクタ内 |
| 静的か | 暗黙的にstatic | インスタンスごとに異なる値可 |
| 適用可能な型 | 値型、string、nullのみ | 任意の型 |
ベストプラクティス
- フィールドは
privateにし、プロパティで公開する - コンストラクタで必須の依存関係を注入し、オブジェクトを常に有効な状態にする
- デストラクタではなく
IDisposableとusingでリソース管理する - 静的メンバーはスレッドセーフティに注意して設計する
- 不変オブジェクトを作る場合は
readonlyフィールドと初期化専用プロパティを活用 - レコード型(C# 9.0+
record)を検討し、値ベースの等価性とwith式を活用
C言語
- C# クラスとオブジェクト:堅牢な OOP の基礎
- C# アクセス修飾子を理解する:public、private、protected、internal など
- C# static キーワード:静的変数、メソッド、クラスをマスターする
- C# 抽象クラスと抽象メソッドをマスターする:実践ガイド
- C# 入れ子クラスを理解する:定義、使用法、継承
- C++クラスとオブジェクト完全ガイド:オブジェクト指向プログラミングの実践
- C言語のストレージクラス:スコープ、ライフタイム、使い分け
- C++ストレージクラス完全解説:スコープ、ライフタイム、使い方
- C++インターフェース完全理解:抽象クラスと純粋仮想関数
- C#プログラム構造の理解:コアコンポーネントと例
- C#基礎:基本構文とオブジェクト指向概念をマスター