クラス
クラスはオブジェクト指向型言語で使われる型です。一見すると構造体と変わらないように見えますが、メソッドも定義することができます。メンバにスコープを宣言することで内部で使うメンバと外部で使うメンバを宣言することもできます。
クラスを定義するときは構造体と同様に class を使い、型名を書いた後、 {} 内で使用するメンバを書いていきます。列挙型と異なるのはメンバには型を入れなくてはなりません。また、メンバの文末には ;(セミコロン) を付けなくてはなりません。
クラスを使うときはこれまでの型と同様に宣言して使いますが、宣言しただけでは使えずクラスを元に生成したオブジェクトを使います。このオブジェクトのことをインスタンスと呼びます。ただし、クラスは静的クラスのようにクラスそのものを扱う場合もあります。
インスタンス
インスタンスとはクラスを基に生成したオブジェクトの実体をさします。プログラム上で使われるのは主にインスタンスです。クラスは設計図でインスタンスは設計図を元にした建物と表現されたり、動物に例えると猫というクラスがあってタマというインスタンスがいると表現されます。
インスタンスは生成した時点でメモリ上に領域が確保されます。インスタンスを生成するときには配列の宣言と同様に new 演算子を用います。
使い終わった後はガベージコレクションがあるためそのままにしても構いません。 C++ のように delete を使うことはできませんが IDispose インターフェイスの Dispose メソッドを使うことでインスタンスが不必要になったときの処理を行うことができます。
また、 IDispose インターフェイスは using ステートメントと組み合わせることができます。 using ステートメントと IDispose インターフェイスについては C# の機能で解説します。
クラスとインスタンスの使用例 ソース
using System;
namespace CSharpCource
{
// 人物型のクラス。
class Profile
{
public string name; // 名前。
public DateTime birthday; // 誕生日。
public int age; // 年齢。
}
class Cource040100
{
// メインメソッド。
static void Main()
{
// インスタンスの宣言。
Profile foo;
// インスタンスの生成。
foo = new Profile();
foo.name = "HOGE";
foo.birthday = new DateTime(1999, 4, 1);
foo.age = 10;
// foo の値を出力します。
Sub(foo);
// インスタンスの宣言と生成を同行に行うこともできます。
Profile bar = new Profile();
bar.name = "PIYO";
bar.birthday = new DateTime(2000, 3, 31);
bar.age = 9;
// bar の値を出力します。
Sub(bar);
}
// サブメソッド。
static void Sub(Profile pro)
{
// 人物型の値を出力します。
Console.WriteLine("名前 : {0}", pro.name);
Console.WriteLine(
"生年月日 : {0}",
pro.birthday.ToString("yyyy/MM/dd"));
Console.WriteLine("年齢 : {0}歳", pro.age);
}
}
}
クラスとインスタンスの使用例 出力結果
名前 : HOGE 生年月日 : 1999/04/01 年齢 : 10歳 名前 : PIYO 生年月日 : 2000/03/31 年齢 : 9歳
C 言語を知っている方は new がメモリ領域確保するための malloc 関数 / calloc 関数と似た働きをすると捕らえても構いません。当然ですが、 C 言語には後に解説するコンストラクタやデストラクタがありません。なので、あくまで似た働きをするものと解釈してください。
コンストラクタとデストラクタに関してはコンストラクタとデストラクタで解説します。
クラスとインスタンスの間違った使用例
using System;
namespace CSharpCource
{
// 人物型のクラス。
class Profile
{
public string name; // 名前。
public DateTime birthday; // 誕生日。
public int age; // 年齢。
}
class Cource040101
{
// メインメソッド。
static void Main()
{
// インスタンスの宣言。
Profile foo, bar, baz;
// インスタンスを生成せずに使用することはできない。
foo.name = "HOGE";
foo.birthday = new DateTime(1999, 4, 1);
foo.age = 10;
// インスタンスの生成で型の後を()で括らないと、
// 使用することはできない。
bar = new Profile;
bar.name = "PIYO";
bar.birthday = new DateTime(2000, 3, 31);
bar.age = 9;
// インスタンスの生成。
baz = new Profile();
// delete を使うことはできない。
delete baz;
}
}
}
クラスの初期化 
クラスのメンバは宣言した行で初期化を行うことができます。なお、この初期化の方法は構造体ではできませんので注意してください。
クラスの初期化の例 ソース
using System;
namespace CSharpCource
{
// 人物型のクラス。
class Profile
{
// メンバの宣言と同時に初期化することができます。
public string name = ""; // 名前。
public DateTime birthday =
new DateTime(1900, 1, 1); // 誕生日。
public int age = 0; // 年齢。
}
class Cource040102
{
// メインメソッド。
static void Main()
{
// インスタンスの宣言と生成。
Profile foo = new Profile();
Sub(foo);
}
// サブメソッド。
static void Sub(Profile pro)
{
// 人物型の値を出力します。
Console.WriteLine("名前 : {0}", pro.name);
Console.WriteLine(
"生年月日 : {0}",
pro.birthday.ToString("yyyy/MM/dd"));
Console.WriteLine("年齢 : {0}歳", pro.age);
}
}
}
クラスの初期化の例 出力結果
名前 : 生年月日 : 1900/01/01 年齢 : 0歳
メソッド
オブジェクト指向型言語ではクラスのメンバとしてメソッド (関数) を入れることができます。厳密に構造化プログラミングで解説したとおりメソッドとはクラスのメンバの一種です。
上のソースでは年齢を直接入れていましたが、これでは誕生日を迎えるたびにビルドし直さないといけないので非常に不便です。誕生日がすでに入力されているので誕生日と現在の日付を元に年齢を取得するメソッドを作ります。
年齢取得メソッドを使った例 ソース
using System;
namespace CSharpCource
{
// 人物型のクラス。
class Profile
{
public string name = ""; // 名前。
public DateTime birthday =
new DateTime(1900, 1, 1); // 誕生日。
// 年齢取得メソッド。
public int GetAge()
{
DateTime now = DateTime.Now;
int age = now.Year - birthday.Year;
// 現在月が誕生月超の場合はそのまま戻す。
if (now.Month > birthday.Month)
{
return age;
}
else if (now.Month == birthday.Month)
{
// 現在日が誕生日以上の場合はそのまま戻す。
if (now.Day >= birthday.Day)
{
return age;
}
}
// それ以外の場合は 1 引いて戻す。
return age - 1;
}
}
class Cource040103
{
// メインメソッド。
static void Main()
{
// インスタンスの宣言と生成。
Profile foo = new Profile();
foo.name = "HOGE";
foo.birthday = new DateTime(1999, 4, 1);
Sub(foo);
}
// サブメソッド。
static void Sub(Profile pro)
{
// 人物型の値を出力します。
Console.WriteLine("名前 : {0}", pro.name);
Console.WriteLine(
"生年月日 : {0}",
pro.birthday.ToString("yyyy/MM/dd"));
Console.WriteLine("年齢 : {0}歳", pro.GetAge());
}
}
}
年齢取得メソッドを使った例 実行結果 (2010/02 に実行した例)
名前 : HOGE 生年月日 : 1999/04/01 年齢 : 10歳
このようにメソッド化することで年齢を一々書き換えなくてすむようになります。
注意。この年齢の割り出し方は法律上の割り出し方と違います。法律上では誕生日の一日前に年齢が上がります。
クラスの入れ子
クラスもまた、構造体と同じく入れ子にすることができます。
クラスに別のクラスや列挙型をメンバに入れた例 ソース
using System;
namespace CSharpCource
{
// 人物型のクラス。
class Profile
{
public string name = ""; // 名前。
public DateTime birthday =
new DateTime(1900, 1, 1); // 誕生日。
public BloodType blood; // 血液型。
public AddressType home =
new AddressType(); // 自宅。
public AddressType office =
new AddressType(); // 勤務先。
// 年齢取得メソッド。
public int GetAge()
{
DateTime now = DateTime.Now;
int age = now.Year - birthday.Year;
// 現在月が誕生月超の場合はそのまま戻す。
if (now.Month > birthday.Month)
{
return age;
}
else if (now.Month == birthday.Month)
{
// 現在日が誕生日以上の場合はそのまま戻す。
if (now.Day >= birthday.Day)
{
return age;
}
}
// それ以外の場合は 1 引いて戻す。
return age - 1;
}
}
// 血液型の列挙型。
enum BloodType
{
A, // A 型。
B, // B 型。
O, // O 型。
AB // AB 型。
}
// 住所型のクラス。
class AddressType
{
public string kind = ""; // 種類。
public string zip = ""; // 郵便。
public string address = ""; // 住所。
public string tel = ""; // TEL。
public string mail = ""; // メール。
}
class Cource040102
{
// メインメソッド。
static void Main()
{
// インスタンスの宣言と生成。
Profile foo = new Profile();
// 人物型の値を設定します。
foo.name = "HOGE";
foo.birthday = new DateTime(1999, 4, 1);
foo.blood = BloodType.AB;
foo.home.kind = "現住所";
foo.home.zip = "000-0000";
foo.home.address = "HOGE 県 PIYO 市 FUGA 町 1-2-3";
foo.home.tel = "000-000-0000";
foo.home.mail = "hoge@hoge.xxx.xxx";
foo.office.kind = "勤務先";
foo.office.zip = "001-0000";
foo.office.address = "FOO 県 BAR 市 BAZ 町 8-9-0";
foo.office.tel = "00-1000-0000";
foo.office.mail = "hoge@foo.yyy.yyy";
SubA(foo);
}
// サブメソッド A 。
static void SubA(Profile pro)
{
// 人物型の値を出力します。
Console.WriteLine("名前 : {0}", pro.name);
Console.WriteLine(
"生年月日 : {0}",
pro.birthday.ToString("yyyy/MM/dd"));
Console.WriteLine("年齢 : {0} 歳", pro.GetAge());
Console.WriteLine("血液型 : {0} 型", pro.blood);
SubB(pro.home);
SubB(pro.office);
}
// サブメソッド B 。
static void SubB(AddressType at)
{
// 住所型の値を出力します。
Console.WriteLine("{0}", at.kind);
Console.WriteLine(" 郵便番号 : {0}", at.zip);
Console.WriteLine(" 住所 : {0}", at.address);
Console.WriteLine(" TEL : {0}", at.tel);
Console.WriteLine(" MAIL : {0}", at.mail);
}
}
}
クラスに別のクラスや列挙型をメンバに入れた例 出力結果
名前 : HOGE 生年月日 : 1999/04/01 年齢 : 11 歳 血液型 : AB 型 現住所 郵便番号 : 000-0000 住所 : HOGE 県 PIYO 市 FUGA 町 1-2-3 TEL : 000-000-0000 MAIL : hoge@hoge.xxx.xxx 勤務先 郵便番号 : 001-0000 住所 : FOO 県 BAR 市 BAZ 町 8-9-0 TEL : 00-1000-0000 MAIL : hoge@foo.yyy.yyy
